August 28, 2003 at 1:53 pm
We have a script to get the first available ID number in a table. We are looking for a faster way to write this.
Here is the script.
Select top 1 ISNULL((Select count(BudgetID) from tblBudgetYear where BudgetID <= Bud.BudgetID), MAX(BudgetID)+1)
from tblBudgetYear Bud
where (Select count(BudgetID) from tblBudgetYear where BudgetID <= Bud.BudgetID)
not in (Select BudgetID from tblBudgetYear)
group by bud.budgetID
Table tblbudgetyears
One field budgetid of type int.
Sample data:
3,4,5,7
Query would return 1
Sample Data2:
1,3,4,5,7
Query would return 2
Sample Data3:
1,2,3,4,5
Query would return 6
August 28, 2003 at 2:09 pm
CREATE PROCEDURE GetFirstAvailableBudgetID
AS
SET NOCOUNT ON
--
DECLARE @Temp TABLE ([TempID] INT IDENTITY(1,1))
DECLARE @MaxCurrentBudget INT, @i INT
-- Grab the highest current budget
SELECT @MaxCurrentBudget = MAX(BudgetID) FROM tblBudgetYear
-- Populate Lookup
SET @i = 0
WHILE @i < @MaxCurrentBudget BEGIN
INSERT INTO @Temp DEFAULT VALUES
SET @i = @i + 1
END
--
SELECT TOP 1 tt.TempID
FROM @Temp tt
LEFT JOIN tblBudgetYear b
ON tt.TempID = b.BudgetID
WHERE b.BudgetID IS NULL
--
SET NOCOUNT OFF
GO
HTH,
Jay
August 28, 2003 at 2:40 pm
Thanks for the reply. It was a little slower than the one we had. We have found one a little faster than the first post.
Select top 1 B.CID from
(Select (Select count(BudgetID) from tblBudgetYear where BudgetID <= Bud.BudgetID) CID from tblBudgetYear bud) B
where B.CID not in (Select BudgetID from tblBudgetYear)
August 29, 2003 at 12:40 am
Try it with NOT EXISTS instead of NOT IN:
...
SELECT MIN(tt.TempID)
FROM @Temp tt
WHERE NOT EXISTS (SELECT * FROM tblBudgetYear)...
August 29, 2003 at 1:46 am
use IDENTITY. That's what it's made for.
Or keep your own parameter-file which you access using a genereate-new-id stored procedure.
Johan
Learn to play, play to learn !
Dont drive faster than your guardian angel can fly ...
but keeping both feet on the ground wont get you anywhere :w00t:
- How to post Performance Problems
- How to post data/code to get the best help[/url]
- How to prevent a sore throat after hours of presenting ppt
press F1 for solution, press shift+F1 for urgent solution 😀
Need a bit of Powershell? How about this
Who am I ? Sometimes this is me but most of the time this is me
August 29, 2003 at 4:21 am
Try this...
SELECT ISNULL(min(BudgetId),
ISNULL((SELECT max(BudgetId) + 2
FROM tblBudgetYear), 2) - 1
FROM tblBudgetYear t1
WHERE NOT EXISTS
(SELECT 1 FROM tblBudgetYear t2
WHERE t2.BudgetId = t1.BudgetId - 1)
AND t1.BudgetId > 1
August 29, 2003 at 4:22 am
By the way alzdba, IDENTITY does not reuse values that have been deleted...
August 29, 2003 at 4:43 am
How About this
declare @j-2 int
declare @i int
set @j-2=1
declare a cursor for
select [column] from
order by [column]
open a
fetch next from a into @i
while @@fetch_status=0
begin
if @i<>@j
begin
break
end
set @j-2=@j+1
fetch next from a into @i
end
print @j-2
close a
deallocate a
Pay Respect to People on your way up. For you will meet the same People on your way down.
He who knows others is learned but the wise one is one who knows himself.
August 29, 2003 at 5:09 am
Hi reeder17,
quote:
We have a script to get the first available ID number in a table. We are looking for a faster way to write this.
sorry for hooking right in
Do you need this sequential numbering being stored with your table?
Or do you need it only for presentational stuff?
If you need it only for presentational stuff what about doing something like this
SELECT
t2.BudgetID, <other_fields>,
(SELECT COUNT(*) FROM <your_table> t1 WHERE t1.BudgetID <= t2.budgetID) AS MyID
FROM
<your_table> t2
ORDER BY
3
Cheers,
Frank
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
August 29, 2003 at 6:33 am
Thanks for all the posts! We are using this instead of an identity column. We have been able to tweak our query; here is the fastest one that we have ran, we tested with all the posts too.
Select top 1 ISNULL(B.CID,ISNULL(MAX(b.budgetid),0)+1) from
(Select budgetid, 'cid'=(Select count(BudgetID)
from tblBudgetYear where BudgetID <= Bud.BudgetID) from tblBudgetYear bud) B
group by B.CID, B.BudgetID
HAVING B.CID <> B.BudgetID
We probably could use an identity column instead of this way, just not sure what happens when it reaches the max size of size int.
August 29, 2003 at 6:51 am
When the identity reaches the maximum for an int. It will stop accepting records (overflow error).
The only way around this is using a GUID column, but that adds some overhead (and storage too).
August 29, 2003 at 7:21 am
quote:
...just not sure what happens when it reaches the max size of size int...
Gee, that's a lot of budgets. You, know, the IDENTITY field was designed for this. It would be a LOT faster, easier, and simpler to use the tools that were designed for the job instead of re-invent the wheel. The max size limit of INT is over 2 trillion, so I don't think you're going to be coming anywhere near that, and if you do, your solution of finding available IDs would be so slow that you'd scrap the idea long before the ID value reached the millions...
August 29, 2003 at 11:09 am
OK Identity does not reuse. Should it ? Depends on the requirements. If your id column reaches the maximum value (int/bigint !!), you're in big troubles anyway and probably you'll have to adjust you id-producing algorithm. With Identity you could checkident and go on. Besides it one should never deduct anything from an id (low id is older than high id) so who cares about gaps. If you use GUID, you cannot deduct anything, but does your datamodel need that overhead ? There's a lot of info in the net regarding identity and surogate-keys.
Johan
Learn to play, play to learn !
Dont drive faster than your guardian angel can fly ...
but keeping both feet on the ground wont get you anywhere :w00t:
- How to post Performance Problems
- How to post data/code to get the best help[/url]
- How to prevent a sore throat after hours of presenting ppt
press F1 for solution, press shift+F1 for urgent solution 😀
Need a bit of Powershell? How about this
Who am I ? Sometimes this is me but most of the time this is me
August 31, 2003 at 6:16 am
How about this:
DECLARE @NewBudgetID INT
IF (Select Min(BudgetID) as NewBudgetID from tblBudgetYear) > 1
Set @NewBudgetID = 1
ELSE
Select @NewBudgetID = top 1 BudgetID + 1 from tblBudgetYear x
where not exists(Select NULL from tblBudgetYear where BudgetID = x.BudgetID + 1)
order by BudgetID
On the occaisions where the value 1 is available, the longer query doesn't execute.
September 1, 2003 at 1:47 am
quote:
Gee, that's a lot of budgets. You, know, the IDENTITY field was designed for this. It would be a LOT faster, easier, and simpler to use the tools that were designed for the job instead of re-invent the wheel. The max size limit of INT is over 2 trillion, so I don't think you're going to be coming anywhere near that, and if you do, your solution of finding available IDs would be so slow that you'd scrap the idea long before the ID value reached the millions...
well said!
I still don't think it's necessary to keep ongoing numbering stored in the db. I assume in addition to BudgetID there is also stored some client identification ID. So the numbering does not apply to this client but only to the table as a whole.
Anyway, just another thought. What about a delete trigger and a lookup table?
Every time a DELETE operation occurs, BudgetID is stored in the lookup table. Next time one needs to fill the holes, he just needs to query the MIN from this table. Not sure what happens when the INSERT transaction fails and how to catch this.
Just another monday morning, one cup of coffee thought
Cheers,
Frank
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
Viewing 15 posts - 1 through 15 (of 19 total)
You must be logged in to reply to this topic. Login to reply