2009-10-06 36 views
2

執行此操作的最佳方法是什麼?TSQL生成5個字符長度的字符串,數據庫中尚不存在的所有數字[0-9]

我需要生成一個5位長度的字符串,其中所有字符都是數字。但是,我需要能夠執行這個'x'次數(用戶變量)並將這些隨機字符串存儲在數據庫中。此外,我無法生成兩次相同的字符串。舊琴絃將在6個月後被移除。

僞代碼

DECLARE @intIterator INT, 
@intMax 

SET @intIterator = 1 
SET @intMax = 5 (number of strings to generate) 

WHILE @intIterator <= @intMax 
BEGIN 

    -- GENERATE RANDOM STRING OF 5 NUMERIC DIGITS 
    ??? 

    -- INSERT INTO DB IF DOESN'T ALREADY EXIST 
    INSERT INTO TSTRINGS 
    SELECT @RANDOMSTRING 

    IF @@ERROR = 0 
    SET @intIterator = @intIterator + 1 

END 

我知道這可能不是做的最好辦法,所以建議表示讚賞。但真正尋找如何生成數字5長度字符串的想法。

+0

任何特別的原因你這樣做完全在TSQL? – 2009-10-06 20:45:22

+0

除了我需要將使用的5位數字字符串存儲在數據庫中的事實之外呢?我猜不會。 – Brad 2009-10-06 20:55:09

回答

3

All in one。這應該找到@intMax剩餘價值,如果你有(100000 - @intMax)行已經與剛剛@intMax排列離開

INSERT TOP (@intMax) MyTable (RndColumn) 
SELECT 
    RndValue 
FROM 
    (
    SELECT DISTINCT TOP 100000 -- covers potential range from 00000 to 99999 
     RIGHT('00000' + CAST(ABS(CHECKSUM(NEWID())) AS varchar(10)), 5) AS RndValue 
    FROM 
     sys.columns c1, sys.columns c2 
    ) foo 
WHERE 
    NOT EXISTS (SELECT * 
     FROM 
      MyTable T 
     WHERE 
      T.RndColumn = foo.RndValue 
+0

謝謝,這是我用過的答案,儘管最高票數的人解釋了更多的理論,但他忽略了生成字符串的方式。 – Brad 2009-10-08 15:20:24

+0

謝謝。我的答案對我認爲更少的行效果更好,但其他答案更正確,並且可以更好地縮放。 – gbn 2009-10-08 15:39:02

0

你需要邏輯來檢查數字是否存在?

你可以使用下面的方法產生的隨機數:

CREATE FUNCTION RandNumber() 
RETURNS float 
AS 
    BEGIN 
    RETURN (SELECT RandNumber FROM vRandNumber) 
END 

CREATE FUNCTION RandNumber2(@Min int, @Max int) 
RETURNS float 
AS 
BEGIN 
RETURN @Min + (select RandNumber from RetRandNumber) * (@[email protected]) 
END 

然後,只需調用RandNumber在你的選擇。

下面是我發現這個腳本的網站:Here

+0

謝謝,但我不需要一個隨機數。我需要一個只使用數字的隨機5位字符串。例如,這可能會返回12,在那裏我需要00012. – Brad 2009-10-06 20:54:24

0

像這樣的事情?

CREATE FUNCTION RandNumber2(@Min int, @Max int) 
RETURNS float 
AS 
BEGIN 
    DECLARE @TheNumber INT 

    SET @TheNumber = (SELECT CONVERT(INT, Rand()*(@[email protected])[email protected])) 

    WHILE (SELECT COUNT(IndexColumn) WHERE CONVERT(INT, IndexColumn) = @TheNumber) > 0 
    BEGIN 
    -- Do it again - we have a collision 
    SET @TheNumber = (SELECT CONVERT(INT, Rand()*(@[email protected])[email protected])) 
    END 

    DECLARE @Result VARCHAR(5) 
    SET @Result = RIGHT('00000' + CONVERT(VARCHAR(5), @TheNumber), 5) 

    RETURN @Result 

END 
+0

這是無效的 - 你會得到一個錯誤「無效的副作用運營商蘭特'在一個函數中使用」 – 2010-12-29 17:34:59

0

一來產生這樣的字符串的方法是:

DECLARE @Foo char(5) 
SET @Foo = right(str((checksum(newid()) + 100000), 11, 0), 5) 
PRINT @Foo 

至於唯一性,你必須圍繞打造表中的線圈保持預先存在的值,只有(索引!)當生成「新」ID時退出循環。如果兩個單獨的進程以某種方式生成相同的值,並且第二個進程在第二次檢查存在之前沒有在表中輸入,則可能會遇到併發問題......但很多取決於何時以及如何實際使用該值。

6

「顯而易見」的方式可以被描述爲「key = random; while (key already selected) { key = random }」。它工程,但birthday paradox意味着我們的關鍵碰撞增加的機率以驚人的指數速率與已使用的鍵的數量成正比。因此,選擇一個隨機密鑰的平均時間要長於每個新密鑰,並且很可能最終陷入無限或任意長的循環。除了keyOrder

  • 保持一個包含所有預先計算的字符串「00000」表UniqueKeys ..「99999」:

    你好得多生成的密鑰列表前面如下在插入時始終將其初始化爲newId()keyOrder應該被索引。當您需要「生成」一個字符串時,您可以SELECT TOP 1 key FROM UniqueKeys ORDER BY keyOrder,它將在幾乎不變的時間內拉下一個可用的鍵。現在您已擁有一個密鑰,您可以將其從UniqueKeys中刪除,以防止它被重複使用。

  • 每隔六個月,截斷並重新生成UniqueKeys表。這種風格的

優點是相對簡單的實現,幾乎恆定的時間來產生下一個鍵,並且避免了討厭的「檢查是否存在於循環」上面描述的場景。

+0

在給我的答案後回家時,我回想起了幾年前的事情。絕對要走的路。 – 2009-10-07 02:28:36

0

下面是一個基於集合的方法,使用SQL 2005語法(SQL 2008會稍微容易些,但沒有指定)。另外,如果你有一個數字表格,它的大部分可以被刪除。

沒有循環,沒有重複,應該幾乎是瞬時的(假設目標列被索引)。

DECLARE @intMax integer 
SET @intMax = 5 

INSERT INTO TSTRINGS 
SELECT q.nString 
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY (newID())) AS N2, 
      RIGHT(REPLICATE('0', 5) + CONVERT(varchar(5), N), 5) as nString 
      FROM --the subquery below could be replaced by a numbers table 
        (SELECT TOP 100000 
        ROW_NUMBER() OVER (ORDER BY (ac1.Object_ID))-1 AS N 
      FROM Master.sys.columns ac1 
       CROSS JOIN Master.sys.columns ac2 
       CROSS JOIN Master.sys.columns ac3) numbers 

      WHERE RIGHT(REPLICATE('0', 5) + CONVERT(varchar(5), N), 5) 
      NOT IN (SELECT nString FROM TSTRINGS) --check to see if reused 
    ) q 
    WHERE q.N2 <= @intMax 
相關問題