September 13, 2016 at 12:38 pm
Hello, I have a stored procedure that will be executing on a recurring basis at different intervals. There is a field that I need to populate with a random unique number but once I use one, I can never use it again. As this procedure will be called all the time and not just once, how do I ensure that I never use the same random number?
I was generating it with this code: (SELECT FLOOR(RAND()*(100000-1)+1))
But, it occurred to me that there is a small possibility that it could somehow pick the same number as a previous call to the stored procedure?
Do I need to actually store the ID somewhere and tell it not to use one that already exists?
Thanks!
September 13, 2016 at 12:53 pm
amy26 (9/13/2016)
Hello, I have a stored procedure that will be executing on a recurring basis at different intervals. There is a field that I need to populate with a random unique number but once I use one, I can never use it again. As this procedure will be called all the time and not just once, how do I ensure that I never use the same random number?I was generating it with this code: (SELECT FLOOR(RAND()*(100000-1)+1))
But, it occurred to me that there is a small possibility that it could somehow pick the same number as a previous call to the stored procedure?
Do I need to actually store the ID somewhere and tell it not to use one that already exists?
Thanks!
That would be the best and easiest way. You could also store a date/time to identify when the number was consumed, as well. You also wouldn't have to generate the random number. Just consume it from the table and mark the date used.
Here's the code to quickly build such a table. You'd just need to add a PK on the ID column.
WITH cteGenRandomNumber AS
(
SELECT TOP 100000
RandomNumber = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2
)
SELECT RandomNumberID = IDENTITY(INT,1,1)
,RandomNumber
,UsedDate = CAST(NULL AS DATETIME)
INTO dbo.SomeTable
FROM cteGenRandomNumber
ORDER BY NEWID()
;
ALTER TABLE dbo.SomeTable
ADD CONSTRAINT PK_SomeTable PRIMARY KEY CLUSTERED (RandomNumberID)
;
--===== Let's see what we have
SELECT * FROM SomeTable
;
Just consume the random numbers in the order of the PK to keep things simple.
--Jeff Moden
Change is inevitable... Change for the better is not.
September 13, 2016 at 1:34 pm
Further on Jeff's fine answer, here is an alternative which should work if you cannot store the numbers generated, I have used this method to generate 10^10 rows without any collisions so I don't think one has to worry too much.
😎
USE TEEST;
GO
SET NOCOUNT ON;
DECLARE @SAMPLE_SIZE BIGINT = 100000
;WITH T(N) AS (SELECT N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS X(N))
, NUMS(N) AS (SELECT TOP(@SAMPLE_SIZE) ROW_NUMBER() OVER (ORDER BY @@VERSION) AS N FROM T T1,T T2,T T3,T T4,T T5,T T6,T T7,T T8,T T9)
SELECT
NM.N
,CONVERT(DECIMAL(36,0),REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(36),NEWID(),0)
,'-','0'),'A','1'),'B','2'),'C','3'),'D','4'),'E','5'),'F','6'),0) AS UNIQUE_NUM
FROM NUMS NM;
First few rows of the output (wich obviously will not be the same again)
N UNIQUE_NUM
-------------------------------------------
1 135175280625604130093760626242760535
2 126112660613304485024340173516872486
3 511616110275204328082710641217492608
4 214653100416404716014530825155544862
5 234911220889404355097210824236653996
6 643090860043504550026840435544739832
7 381081880930804333016160303718724276
8 624900120545204632096120595995822513
9 566613250226104696012050243933148314
10 863626410665604637087640542153222212
11 192442310305904210018950337740554465
12 837567600538204979087070496244413015
13 16147680206204593095330155291383156
14 261269930123004044081180553099435328
15 11666800438804655099720790666812479
16 53364480316004907091920270442425738
17 258143540106504560025150789225079433
18 683828320155404239082920964216552067
19 894193660453904049026540658420239837
20 466639730433104583028070722245642288
September 14, 2016 at 6:31 am
Thank you so much! Perfect!
September 14, 2016 at 7:42 am
Eirikur Eiriksson (9/13/2016)
First few rows of the output (wich obviously will not be the same again)
Not guaranteed to be true, though. Because of the translations, as unlikely as it would be, there could be a duplicate even in such a short list. My suggestion would be that it's better to go with the guaranteed list of non-duplicate numbers.
--Jeff Moden
Change is inevitable... Change for the better is not.
September 14, 2016 at 8:15 am
Jeff Moden (9/14/2016)
Eirikur Eiriksson (9/13/2016)
First few rows of the output (wich obviously will not be the same again)Not guaranteed to be true, though. Because of the translations, as unlikely as it would be, there could be a duplicate even in such a short list. My suggestion would be that it's better to go with the guaranteed list of non-duplicate numbers.
As the generated UUID from NEWID is RFC4122 compliant (according to MS) then it is very unlikely that it would happen on a single system (built in 2 sequential bytes), the problem may more likely show up when the values are generated on multiple systems.
The caveat is that there are "only" 3.4 × 10^38 values within this format.
😎
September 14, 2016 at 5:17 pm
Eirikur Eiriksson (9/14/2016)
Jeff Moden (9/14/2016)
Eirikur Eiriksson (9/13/2016)
First few rows of the output (wich obviously will not be the same again)Not guaranteed to be true, though. Because of the translations, as unlikely as it would be, there could be a duplicate even in such a short list. My suggestion would be that it's better to go with the guaranteed list of non-duplicate numbers.
As the generated UUID from NEWID is RFC4122 compliant (according to MS) then it is very unlikely that it would happen on a single system (built in 2 sequential bytes), the problem may more likely show up when the values are generated on multiple systems.
The caveat is that there are "only" 3.4 × 10^38 values within this format.
😎
Agreed to all of that but "unlikely" does not mean "impossible". My luck at such things has been pretty bad lately and I just don't take such chances because I don't have the time to do it more than once. Takes less time to do it with a guarantee just once. 🙂
--Jeff Moden
Change is inevitable... Change for the better is not.
September 14, 2016 at 5:18 pm
amy26 (9/14/2016)
Thank you so much! Perfect!
Curiosity question please. Which method did you use?
--Jeff Moden
Change is inevitable... Change for the better is not.
September 14, 2016 at 9:05 pm
Jeff Moden (9/14/2016)
amy26 (9/14/2016)
Thank you so much! Perfect!Curiosity question please. Which method did you use?
The table.
But I added more rows.
September 14, 2016 at 11:42 pm
Jeff Moden (9/14/2016)
Eirikur Eiriksson (9/14/2016)
Jeff Moden (9/14/2016)
Eirikur Eiriksson (9/13/2016)
First few rows of the output (wich obviously will not be the same again)Not guaranteed to be true, though. Because of the translations, as unlikely as it would be, there could be a duplicate even in such a short list. My suggestion would be that it's better to go with the guaranteed list of non-duplicate numbers.
As the generated UUID from NEWID is RFC4122 compliant (according to MS) then it is very unlikely that it would happen on a single system (built in 2 sequential bytes), the problem may more likely show up when the values are generated on multiple systems.
The caveat is that there are "only" 3.4 × 10^38 values within this format.
😎
Agreed to all of that but "unlikely" does not mean "impossible". My luck at such things has been pretty bad lately and I just don't take such chances because I don't have the time to do it more than once. Takes less time to do it with a guarantee just once. 🙂
You are right Jeff, a single source table is the best option if possible and guaranteed to be unique. How many times have we seen collisions in unique identifiers like MAC addresses, IMEI, SSN etc.;-)
😎
Viewing 10 posts - 1 through 9 (of 9 total)
You must be logged in to reply to this topic. Login to reply