保证随机插入

Gio*_*uri 6 sql sql-server

我试图预生成一些字母数字字符串并将结果插入表中.字符串的长度为5.示例:a5r67.基本上我想为客户生成一些可读字符串,以便他们可以访问他们的订单 www.example.com/order/a5r67.现在我有一个select语句:

;WITH 
    cte1 AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t)),
    cte2 AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t)),
    cte3 AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t)),
    cte4 AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t)),
    cte5 AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t))
INSERT INTO ProductHandles(ID, Used)
SELECT cte1.t + cte2.t + cte3.t + cte4.t + cte5.t, 0
FROM cte1
CROSS JOIN cte2
CROSS JOIN cte3
CROSS JOIN cte4
CROSS JOIN cte5
Run Code Online (Sandbox Code Playgroud)

现在的问题是我需要写这样的东西来从表中获取一个值:

SELECT TOP 1 ID 
FROM ProductHandles
WHERE Used = 0
Run Code Online (Sandbox Code Playgroud)

我将在Used列上有索引,所以它会很快.这个问题是它带有顺序:

00000
00001
00002
...
Run Code Online (Sandbox Code Playgroud)

我知道我可以订购NEWID(),但这会慢得多.我知道除非我们指定Order By条款,否则无法保证订购.需要的是相反的.我需要保证混乱,但不是NEWID()每次客户创建订单时都要订购.

我将使用它像:

WITH cte as (
                SELECT TOP 1 * FROM ProductHandles WHERE Used = 0
                --I don't want to order by newid() here as it will be slow
            )
UPDATE cte 
SET Used = 1
OUTPUT INSERTED.ID
Run Code Online (Sandbox Code Playgroud)

Zoh*_*led 8

如果添加标识列的表,并使用order by newid()插入记录时(这将是缓慢的,但它是一个的被从我了解离线进行一次性的事情),那么你可以使用order byidentity列,选择记录的顺序他们插在桌子上.

来自Microsoft Docs中页面限制和限制部分INSERT:

使用SELECT和ORDER BY来填充行的INSERT查询保证了如何计算标识值,但不保证插入行的顺序.

这意味着,通过执行此操作,您可以有效地使identity列按照与insert...select语句中选定的行相同的随机顺序排序.

此外,没有必要重复相同的cte 5次 - 你已经在重复交叉申请:

CREATE TABLE ProductHandles(sort int identity(1,1), ID char(5), used bit)


;WITH 
    cte AS(SELECT * FROM (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('a'),('b'),('c'),('d'),('e'),('f'),('g'),('h'),('i'),('j'),('k'),('l'),('m'),('n'),('o'),('p'),('q'),('r'),('s'),('t'),('u'),('v'),('w'),('x'),('y'),('z')) AS v(t))        
INSERT INTO ProductHandles(ID, Used)
SELECT a.t + b.t + c.t + d.t + e.t, 0
FROM cte a
CROSS JOIN cte b
CROSS JOIN cte c
CROSS JOIN cte d
CROSS JOIN cte e
ORDER BY NEWID()
Run Code Online (Sandbox Code Playgroud)

然后cte可以有一个order by子句,它保证了与填充此表的select语句返回的行相同的随机顺序:

WITH cte as (
                SELECT TOP 1 * 
                FROM ProductHandles 
                WHERE Used = 0
                ORDER BY sort 
            )
UPDATE cte 
SET Used = 1
OUTPUT INSERTED.ID
Run Code Online (Sandbox Code Playgroud)

您可以在rextester上看到现场演示.(只有数字,因为它花了太长时间)