Google Answers Logo
View Question
 
Q: SQL (using MS SQL Server 2000 & ASP) ( Answered 5 out of 5 stars,   8 Comments )
Question  
Subject: SQL (using MS SQL Server 2000 & ASP)
Category: Computers > Programming
Asked by: krickles-ga
List Price: $75.00
Posted: 13 Apr 2003 19:29 PDT
Expires: 13 May 2003 19:29 PDT
Question ID: 190141
Problem: Trying in vain for a query that will at a minimum supply me
with the next available unused number from a table or will generate a
list of unused numbers (my preference) from the main table without
using a look up table.

Details:  Have a table with control_number (numeric, 9, with
identity); record_number (numeric, 9); proj_name (varchar 50);
proj_location (varchar 50); inactive (bit).  The control_number table
is my primary key.  The record_number is generated by the user and can
be reused.  Each user has a set of numbers assigned to him/her (e.g.,
Susie has 100-199, Greg has 200-299).  The users want to see what
record_numbs are available when entering new records.  Any record
flagged inactive is available for use again.

Attempts:

select min(record_numb) + 1 from add_project where not exists (select
min(record_numb) from add_project)  [Yields NULL]

select min(record_numb) + 1 from add_bid_main where record_numb not
between 1 and 10000 group by record_numb having min(record_numb)+1 <>
record_numb [Yields nothing, not even a NULL]

Please help.  Regards, Krickles

Request for Question Clarification by hammer-ga on 14 Apr 2003 04:36 PDT
Please list the fields in add_project and add_bid_main. From which of
these two tables do you need the list of unused record_numb's?

- Hammer

Request for Question Clarification by hammer-ga on 14 Apr 2003 04:37 PDT
Or is it the control_number table that has the list?

- Hammer

Request for Question Clarification by mathtalk-ga on 14 Apr 2003 04:49 PDT
Hi, Krickles-ga and Hammer-ga:

It is possible to give a "simple" query that returns the lowest unused
record number (for a particular user) if there is one, although it is
not clear whether this is what is meant by the "next" record number.

In the absence of a table that explicitly lists the user's range of
record numbers, I think the only practical approach that returns a
complete list of available record numbers would require a stored
procedure.  Is that allowed?

regards, mathtalk-ga

Clarification of Question by krickles-ga on 14 Apr 2003 18:37 PDT
See comments section.

Request for Question Clarification by mathtalk-ga on 14 Apr 2003 20:41 PDT
Hi, krickles:

I guess the most urgent question for you to address is whether you can
use stored procedures in your application or not.

Perhaps in using ASP to code the front-end of your application you
have avoid using them.  However if you are using ADO to connect to the
SQL Server 2000 database, using stored procedures might very well
improve the readability and robustness of your application, e.g. by
improving parameter handling and by providing a further concentration
of business logic on the database side rather than in the Web pages.

See my comment/suggestions below for more details.

regards, mathtalk

Clarification of Question by krickles-ga on 14 Apr 2003 20:47 PDT
Yes, stored procedures are fine.
Answer  
Subject: SQL Server Stored Procedure Tutorial
Answered By: mathtalk-ga on 15 Apr 2003 08:54 PDT
Rated:5 out of 5 stars
 
Hi, krickles-ga:

Let's start with a stored procedure that inserts a bunch of records
into a big "lookup" table, as this affords an opportunity to set the
stage by creating the tables we will need to demonstrate the
principles, and also to describe the basics one needs to know to work
with stored procedures.

I'm going to assume you are using the Query Analyzer tool for SQL
Server 2000 and have a reasonable familiarity with it.  If I ask you
to do something that doesn't make sense, please let me know; I'll be
happy to clarify.

Here are the creation statements for three tables, a very simplified
version of your add_project table (focusing just on the two columns
that are relevant), a table user_range as I described before to hold
the parameters for which user will own which range of record numbers,
and finally table big_lookup (the target of this initial exercise).

CREATE TABLE add_project (
  record_number integer  not Null,
  inactive bit Null
  )
go

CREATE TABLE user_range (
  usersid       char(10) not Null,
  min_num       integer  not Null,
  max_num       integer  not Null
  )
go

CREATE TABLE big_lookup (
  usersid       char(10) not Null,
  rec_num       integer  not Null
  )
go

ALTER TABLE user_range ADD PRIMARY KEY (usersid)
go

INSERT into user_range VALUES ('Susie', 100, 199)

INSERT into user_range VALUES ('Greg',  200, 299)

The above SQL statements set the stage for us to talk about writing a
stored procedure that can churn out a bunch of lookup records,
inserting them into table big_lookup without a lot of tedious typing.

First I'll give you a stored procedure build_lookup that does some
inserting based on some explicit parameters.  You'll note that I being
the scripting with a statement to DROP the existing stored procedure
(if any).   This is a good programming practice when working with
stored procedure scripting.  Of course, the first time we do this the
database will tell us it cannot drop the stored procedure, because it
doesn't exist!  But this doesn't hurt to try, in any case.

DROP   PROC build_lookup
go

CREATE PROC build_lookup 
  @usersid  char(10),
  @min_num  integer,
  @max_num  integer
AS
BEGIN
  SET NOCOUNT ON

  DECLARE @I INTEGER
  SELECT  @I = @min_num

  WHILE @I <= @max_num
  BEGIN
    INSERT into big_lookup VALUES (@usersid,@I)
    SELECT @I = @I + 1
  END

  SET NOCOUNT OFF
END

Before we discuss what the above stored procedure does and how, let's
first test it out.  You should execute these next three statements one
at a time (you can select one (highlight it) in the Query Analyzer
window where you are trying this out, and hit Ctrl-E (for execute).

build_lookup 'Jane', 0, 99

select * from big_lookup

truncate table big_lookup

The first of these three test statements calls the stored procedure
and passes in the three values as arguments, in corresponding order. 
The second statement then shows us that we have successfully inserted
100 records into the table.  Finally the last statement (truncate) is
a convenient way to delete everything in the table big_lookup, so we
go back to having a clean slate there.

So let's talk about how the stored procedure build_lookup does this
work.  The first thing you notice about the CREATE PROC or CREATE
PROCEDURE code is that it defines the parameters of the stored
procedure right after the name of the stored procedure.  Each
parameter is assigned a datatype, and they are separated by commas,
but the list of parameters is not surrounded by parentheses as one
might have expected (say the way column names to a CREATE TABLE script
would be).  The word AS separates the procedure name and list of
parameters from the body of the stored procedure.

Although a stored procedure may consist of a single SQL statement,
more often than not it will involve multiple statements, as it does
here.  We need the "BEGIN...END" pair of statements to form a "block"
of SQL statements that can be parsed & executed together rather than
separately.

The first statement inside the main block is SET NOCOUNT ON.  You
might not have seen this sort of statement before, but it tidies up
the appearance of the the stored procedure's output by suppressing all
the "1 row(s) inserted" messages that we would otherwise get.  You
might want to experiment with commenting this line out (and
re-creating the stored procedure) just to see the difference.

The main point of this stored procedure is the looping over an integer
variable @I (which we had to "declare" in order to use as a local
variable within the stored procedure).  The Transact-SQL programming
language is in many ways very limited, but the WHILE loop will be
adequate for our needs.  Notice that @I is "initialized" before the
loop begins by using a SELECT statement to assign to it the minimum
value.  Thereafter the loop is responsible for incrementing @I until
it is no longer within the specified range (less than or equal to the
@max_num paramter), at which point the WHILE statement passes control
to the first exectuable statement following the inner "BEGIN...END"
block that defines the body of the WHILE loop.

In this case that happens to be the SET NOCOUNT OFF statement,
restoring the default behaviour of Query Analyzer right before we exit
the stored procedure entirely (because the final END statement marking
the completion of the stored procedure's body).

Now stored procedures can be building blocks for other stored
procedures.  Our next example will illustrate this, and also
introduces a very powerful feature of many stored procedures, the
cursor.

A cursor is essentially a pointer into a set of records returned by a
query.  Here I've written a stored procedure build_user_lookup so that
it will consult the records in the user_range table for us, and pass
those corresponding fields to the "building block" stored procedure
build_lookup that we've already written and tested above:

DROP   PROC build_user_lookup

CREATE PROC build_user_lookup
AS
BEGIN
  SET NOCOUNT ON
  DECLARE range_cursor CURSOR
  FOR
    SELECT usersid, min_num, max_num
    FROM user_range

  OPEN range_cursor

  DECLARE @myusrid  char(10)
  DECLARE @min_num integer, @max_num integer

  -- perform the first FETCH
  FETCH NEXT from range_cursor 
  INTO @myusrid, @min_num, @max_num

  -- loop as long as fetch is successful
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXECUTE build_lookup @myusrid, @min_num, @max_num

    FETCH NEXT from range_cursor
    INTO @myusrid, @min_num, @max_num
  END

  SET NOCOUNT OFF
END

You can test that this stored procedure does the right thing with
these statements (in a Query Analyzer window):

build_user_lookup

select * from big_lookup

truncate table big_lookup

Looking at the text of the build_user_lookup stored procedure, you
will notice that it has no parameters.  It doesn't need them because
it is written simply to perform a global insertion of lookup records
for all the users identified in the user_range table.

Within the body of this stored procedure, we have the usual "wrapping"
of the executable statements by SET NOCOUNT ON... SET NOCOUNT OFF. 
But immediately within that bracketing pair of statements we declare a
cursor range_cursor.

This declare statement is a little more complex than the declare
statements that are used for defining local variables.  It needs to be
because we are associating a SQL query with the cursor, so that when
the cursor is "OPEN"ed later, it actually means to run the SQL query
and make the resulting recordset available through commands like
"FETCH NEXT ... ".

To make a long story short, what we do with the cursor is to perform
an initial FETCH NEXT to get the first record, then go into a WHILE
loop (which checks the fetch status variable pre-defined by the system
to see whether there actually is a next record returned).  Here we
process that record simply by passing the three arguments retrieved by
the underlying SQL query against user_range, as arguments to our
"building block" stored procedure build_lookup.  So long as the cursor
continues to supply more records, the looping continues.  When there
are no more records, the fetch status will become -1 and we exit the
loop.

Please review the sample tables and stored procedures which I've
provided above, and let me know if you have questions or concerns
about them before we dive into the procedures that will answer your
original question (about find the first available or all record
numbers available to a given user).

regards, mathtalk

Clarification of Answer by mathtalk-ga on 16 Apr 2003 11:08 PDT
Hi, krickles-ga:

Thanks for the comment letting me know where you are.  Having laid the
groundwork of table definitions, etc., we can proceed to solving your
original question.

If the big_lookup table were present and fully populated, then a
single SQL query (dependent on a parameter @USERSID which identifies
the user) could be used to give the entire set of "available" record
numbers:

SELECT rec_num FROM big_lookup
WHERE usersid = @USERSID
  AND NOT EXISTS (SELECT * FROM add_project
     WHERE record_number = rec_num
       AND inactive = 0
     )

A slight modification then gives us the smallest available record
number:

SELECT min(rec_num) FROM big_lookup
WHERE usersid = @USERSID
  AND NOT EXISTS (SELECT * FROM add_project
     WHERE record_number = rec_num
       AND inactive = 0
     )

In order to dispense with the big_lookup table we need an alternative
way to "generate" the record numbers which _don't_ exist in the
add_project table.  We first show how to do this with a stored
procedure to find the smallest available record number:

CREATE PROCEDURE get1stAvailableRecNumber
  @USERSID  char(10)
AS
BEGIN

  SET NOCOUNT ON

  DECLARE @REC_NUM INTEGER
  DECLARE @MAX_NUM INTEGER
  
  SELECT @REC_NUM = min_num, @MAX_NUM = max_num
  FROM user_range
  WHERE usersid = @USERSID
  
  WHILE @REC_NUM <= @MAX_NUM AND
    EXISTS (SELECT * FROM add_project
      WHERE record_number = @REC_NUM
        AND inactive = 0
      )
  BEGIN
    SELECT @REC_NUM = @REC_NUM + 1
  END
  
  IF @REC_NUM > @MAX_NUM
    SELECT @REC_NUM = 0
  
  SELECT @REC_NUM AS record_number
  
  SET NOCOUNT OFF
  
END

When we want return the entire set of available record numbers for a
user, only slight modifications are needed, including the creation of
a temporary table to hold the results:

CREATE PROCEDURE getAllAvailableRecNumber
  @USERSID  char(10)
AS
BEGIN

  SET NOCOUNT ON

  DECLARE @REC_NUM INT
  DECLARE @MAX_NUM INT
  
  SELECT @REC_NUM = min_num, @MAX_NUM = max_num
  FROM user_range
  WHERE usersid = @USERSID
  
  CREATE TABLE #t(record_number INT)
  
  WHILE @REC_NUM <= @MAX_NUM 
  BEGIN
    IF NOT EXISTS (SELECT * FROM add_project
      WHERE record_number = @REC_NUM
        AND inactive = 0
      )
      INSERT into #t VALUES (@REC_NUM)
    SELECT @REC_NUM = @REC_NUM + 1
  END
  
  SELECT record_number FROM #t
  
  SET NOCOUNT OFF
  
END

Here the available record numbers are inserted into temporary table #t
as we find them, looping over the user's range.  If there are no
available record numbers, then the table would be empty.  In any case
the resulting record set is returned by the final SELECT statement. 
SQL Server takes care of dropping the temporary table as control
passes out of the scope of the stored procedure where it's created.

As a final piece of code, we look at using a single SQL query to get
the smallest available record number for a user.  The logic of this is
obscure enough to pose a maintenance headache, so it's presented
mainly out of intellectual curiousity.  I have prepended a couple of
lines so that query following may be tested within a Query Analyzer
window (using the test data inserted previously).  All must be
executed together, so hit Ctrl-E without selecting any text (if this
is the only code in the window) or else with just these lines
selected:

DECLARE @USERSID char(10)

SELECT @USERSID = 'Susie'

SELECT CASE
  WHEN NOT EXISTS (SELECT * FROM add_project
    WHERE record_number = min_num
      AND inactive = 0
    )
  THEN min_num
  ELSE
    (SELECT min(record_number) + 1 FROM add_project A
    WHERE  record_number BETWEEN min_num AND (max_num - 1)
      AND  NOT EXISTS (SELECT * FROM add_project B
        WHERE B.record_number = A.record_number + 1
          AND B.inactive = 0
        )
     )
  END
FROM user_range
WHERE usersid = @USERSID

Alternatively you could simple replace the parameter @USERSID at
bottom with constant text 'Susie' or 'Greg'.

In closing I take note of confusedfish-ga's suggestion that this
functionality also could be implemented on the ASP side.  Certainly a
possibility, but testing would be needed to convince me that such an
approach would be faster, once the need to access the database for the
user's range of record numbers and the list of those record numbers
_not_ available is taken into account.

regards, mathtalk-ga

Request for Answer Clarification by krickles-ga on 17 Apr 2003 19:08 PDT
mathtalk:

Everything worked exactly as I requested.  Thanks.  How much total
time did you spend on my questions?  Do you offer any consulting
services?  If so, how may I contact you?

I'll post a high rating and pay accordingly once you answer my first
question above.

Regards,  krickles

Clarification of Answer by mathtalk-ga on 18 Apr 2003 09:17 PDT
Hi, krickles:

Thanks for the kind words of encouragement.  I spent a bunch of hours
on this, but that doesn't translate into an increase in the price
you've already offered for my help.  I'm something of a teacher at
heart, and it is rewarding to do a bit of "knowledge transfer" with
someone with an immediate application.

In order to promote this sort of information exchange, without having
the best customers and the best researchers "drop out" of the program,
the Google Answers terms of service forbid us to arrange contacts
outside of this forum.

I realize the "granularity" of the question and answer format is not a
perfect match for doing project work.  Since the Google Answers
service is still in "beta", suggestions at this point on how to
improve the service can perhaps make a lasting contribution.  There
are many terrific researchers here, and I'm almost constantly
impressed by the extent and quality of results which they provide.

regards, mathtalk

Request for Answer Clarification by krickles-ga on 22 Apr 2003 18:08 PDT
mathtalk-ga:

Sorry it has taken so long to follow up.  I spend a lot of time on the
road.

As a person who hires subcontractors and consultants, I find it
difficult to locate good proven talent before committing said talent
to a project.  I usually go with gut feel for new hires.  Once I find
someone who is a hard worker and intelligent I tend to stick with them
and try to coerce them into things outside of their expertise for the
simple reason I know the person is a good worker and will do his/her
best at the new task.

Online services (e.g., IT Moonlighter), temp firms, and recruiters are
decent ways to find people.  However, I usually discover the best
talent through other people in my industry (word of mouth from
colleagues/peers).  However, my experience on Google Answers (GA) has
been positive…especially with you.  Subsequently, GA should provide a
way for its researchers to further assist clients outside of the GA
environment.

A way this could work for the client, researcher, and GA:  

To help GA stay in the loop (and profit), the researcher(s) should
agree to pay GA a cut from any money received from a client that the
researcher found through the GA portal.  For example, I would like to
explore the possibility of hiring you to come on-site for one or two
days to look through my app’s queries and to teach me some new
techniques.  In this scenario, I would pay travel expenses and a set
rate per day.  GA would receive a percentage of what you earn for your
wage excluding the paid travel expenses.  Say you don’t want to
travel?  Then I should be able to send you a copy of my database and
queries and have phone discussions.  How you and I arrange to continue
our business outside of GA should be between us as long as GA has
their cut.  To help facilitate this, GA could have researchers invoice
through GA’s site.

Just some thoughts.  Your tip is on the way.

Regards,

Keith Rickles

Clarification of Answer by mathtalk-ga on 22 Apr 2003 19:55 PDT
Hi, Keith:

Thanks for the generous words (and tip!).  I'm a travelling kind of
guy, but I'll have to explore your suggestions with the Google Answers
staff.  This month marks the one year anniversary of the GA service,
and I know they have some new concepts in mind.  Hopefully something
will mesh for all of us.

best wishes,
mathtalk
krickles-ga rated this answer:5 out of 5 stars and gave an additional tip of: $50.00
5 stars.  What else is there to say?

Comments  
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: confusedfish-ga on 14 Apr 2003 06:06 PDT
 
You were close with your first attempt but this should get you closer:

@MinRec & @MaxRec need to be defined depending on the user you select,
so for Greg they would be 200 & 299 respectively. If you wanted a
recordset then you could just ommit the first select statement and
just have the bit in the brackets.

select min(record_numb)
from add_project where record_num in (select 
record_numb from add_project where inactive = 0 and
record_numb>=@MinRec and record_numb<=@MaxRec)
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: confusedfish-ga on 14 Apr 2003 06:14 PDT
 
P.S. : I sincerly hope you dont have to pay $75 for this!
P.P.S. : I also hope my code works :-)
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: mathtalk-ga on 14 Apr 2003 07:42 PDT
 
Hi, confusedfish-ga:

I believe that when krickles-ga defined the table above containing the
bit field "inactive", the control_number field was designed as the
primary key.

Therefore an approach which relies on this "inactive" bit to carry
information about available record_number values does not seem valid
to me.  However your approach would be workable _if_ there were a
table that contains all the record numbers.  Unfortunately, as I read
the problem, krickles-ga wishes to avoid precisely this when asking to
"generate a list of unused numbers ... from the main table without
using a look up table."

regards, mathtalk-ga
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: krickles-ga on 14 Apr 2003 18:17 PDT
 
Sorry to take so long for a follow up - been on the road today. 
Anyway, clarification for the questions:

In my two samples, the FROM table should be add_project in both
queries.

The table, add_project, has the following fields in the listed order:

tblAddProject
control_numb (numeric (9), Not Null, Identity)
record_numb (numeric (9), Null)
project_name (varchar (50), Null)
project_location (varchar (50), Null)
general_contractor (varchar (50), Null)
division (varchar (50), Null)
inactive (bit, Null)

I want to be able to load the form field with the next available
lowest number from a group of repeating numbers (this is from the user
defined record_numb field).  For example, Greg has numbers 1-10
available:

1 active
2 active
3 active
4 inactive
5 active
6 active
7-10 inactive

When the form loads, the form field for record_numb should list 4. 
The next listing should be 7.

How can this be done?  Can I create a temp table or virtual table with
a large number range and use that as a look-up table?  I am not
opposed to a look up table, it will just have to be loaded with
numbers 1 through 10,000 (and I don't know how to autoload or batch
load this number range so that I don't have to enter 10000 records in
a lookup table).  I am open to suggestions.

My dream solution will list the next available number and a list of
other available numbers from the range available per user.  This
system is as focused as I can make it on the users, and they are set
on this type of numbering system.  The control_numb is for me to use
in the background to better manage the records considering the
record_numb will be repeated.

Hope this helps.  BTW, I have tried the following to no avail:

SELECT min(record_numb)+1 as rn 
FROM add_project WHERE NOT EXISTS
(SELECT ap.record_numb AS rn, ap1.record_numb as rn1 
FROM add_project as ap 
INNER JOIN add_project as ap1 on ap1.record_numb = ap.record_numb)

I think I need something along the lines of 

SELECT min(record_numb)+1 <> min(record_numb)
FROM add_project

just for the next availble min number, but the syntax won't fly.

Looking forward to the suggestions.  Krickles
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: mathtalk-ga on 14 Apr 2003 19:54 PDT
 
Hi, Krickles:

My suggestions --

Let's be clear on the criterion for a record number to be inactive. 
The number should not appear in the add_project table's record_number
field for any record which has inactive = 0.  If the number appears
only in a record with inactive = 1, or if it doesn't appear on any
record in the table, then it's available for use.

To return the single lowest available record number for a user, you
will need at least a table somewhere that keeps track of the record
number ranges available to each user.  Say user ID's are ten
characters and record numbers are (essentially) integers:

CREATE TABLE user_range (
   user_id char(10) not Null,
   min_num integer  not Null,
   max_num integer  not Null
)

Given such a table, you'd need to pass in as a parameter to your
"simple" query the user ID.  I'm not sure what approach you are taking
to make database calls from the user interface, eg. ADO.  But it often
is simplest to "wrap" even a single SQL query into a stored procedure
to facilitate the parameter handling.

You can easily load a table with 10,000 consecutive integer entries
using a stored procedure;  either Hammer or I could easily write one
for you.  While we're at it we can put the user ID's in the table as
well, through an index on it, and then your queries are pretty
straightforward, e.g.

SELECT rec_num from big_lookup
WHERE user_id = @USERID
  AND NOT EXISTS (SELECT * from add_project
      WHERE .....
  )

or throw a min( ) on the rec_num to get the lowest available one.

But I think you should probably avoid the big lookup table (it just
sits around taking up space, yes?) in favor of using a stored
procedure search for the list of ALL available record numbers for a
given user.  Of course there may be something inherent about the way
your frontend calls the database that makes it a bad idea or
impossible to use stored procedures; let us know if this is the case
here.

regards, mathtalk
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: krickles-ga on 14 Apr 2003 20:35 PDT
 
Stored procedures are fine with me.  

I am using ASP (3.0 not .net) with ADO to connect with my database. 
In my old app I maintained a look up table b/c I only was dealing with
a couple of users.  However, I have been asked to do a major upgrade
(e.g., rewrite) of the app and will have up to 30 users.  I am unsure
of how the numbering convention will end up, but do know that each
user will have a range.  If you will provide an example with the
stored procedure and one user with any range, that should suffice.

BTW, if you will also include how to use a stored procedure to fill up
a table with integers I would like to see that as well.  All of my
previous development experience has been with really small apps and I
have avoided store procedures.  However, with this rewrite I am seeing
the beauty.  Anyway, I am always open to help & advice.

Thanks again.  Krickles
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: krickles-ga on 15 Apr 2003 20:54 PDT
 
Mathtalk:  I am out of town and don't have access to my development
environment.  I'll be in the office Thurs and will test what you have
written and will follow up accordingly.  Speak with you soon,
Krickles.
Subject: Re: SQL (using MS SQL Server 2000 & ASP)
From: confusedfish-ga on 16 Apr 2003 04:45 PDT
 
krickles-ga:

THe syntax you have used here is wrong... you dont want to be using
WHERE NOT EXISTS() but more allong the lines of WHERE NOT IN()

As you have stated that your table add_project layout things are
becoming more clear. If we say that if inactive=1 then ignore this
record (as it doesn't matter if the record_numb is in use anymore) and
if inactive=0 then this record_numb is in use then logically...

SELECT record_numb FROM add_project WHERE inactive=0

will return all record_numb in use? You could then further limit this
recordset by defining some limits for the user @max & @min...

SELECT record_numb FROM add_project WHERE inactive=0 AND
record_numb>=@min AND record_numb<=@max

We could go togreat lengths in SQL to build temp tables or loop round,
cursors or whatever, but the result will be slow, far better to use
ASP...

I assume you can get the recordset out from SQL into a string using
GetString()

so:
dim sMyString
if not oRs.EOF then
sMyString = "," & oRs.GetString(,,",",",") & ","
else
sMyString = ""
end if

We now have the recordset in a string in the form ,1,2,3, where the
numbers are the USED values...

Assuming your ASP knows the min & max limits too then you can just do:

dim iFound
iFound = 0
for i = iMin to iMax
'Now look in the recordset to see if this value is in use
if instr(sMyString,"," &Cstr(i) & ",")=0 then
'This value is not in use
iFound = i
i=iMax+1 'Get out of the loop
end if
next

'Next value or 0 is in iFound

Just a suggestion, there are always a few ways to do the same thing.
Ben.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy