生成sql server中的表中没有的随机数

Ull*_*las 3 sql sql-server sql-server-2008

我正在寻找生成一个随机数,生成的数字不在另一个表上.

例如:如果一个表调用randomNums了值10,20,30,40,50.

我想生成一个除上述值之外的数字.

我尝试了以下查询.

询问

;WITH CTE AS
(
    SELECT FLOOR(RAND()*100) AS rn
)
SELECT rn FROM CTE
WHERE rn NOT IN (SELECT num FROM randomNums);
Run Code Online (Sandbox Code Playgroud)

但有时这个查询什么也不返回.
因为那个时候它会生成表格中的数字randomNums.

如何解决这个问题?

小提琴,供参考

Har*_* CO 11

还有一个选择,我一直喜欢NEWID()随机排序,而且交叉连接可以非常有效地创建很多行:

;with cte AS (SELECT 1 n UNION ALL SELECT 1)
     ,cte2 AS (SELECT TOP 100 ROW_NUMBER() OVER(ORDER BY a.n) n
               FROM cte a,cte b,cte c,cte d, cte e, cte f, cte g)
SELECT TOP 1 n
FROM cte2 a
WHERE NOT EXISTS (SELECT 1
                  FROM randomNums b
                  WHERE a.n = b.num)
ORDER BY NEWID()
Run Code Online (Sandbox Code Playgroud)

演示:SQL小提琴


Gio*_*sos 5

如果您不想使用WHILE循环,那么您可以考虑使用递归的解决方案CTE

;WITH CTE AS
(
    SELECT FLOOR(RAND()*100) AS rn  

    UNION ALL

    SELECT s.rn 
    FROM (
       SELECT rn      
       FROM CTE 
       WHERE rn NOT IN (SELECT num FROM randomNums)                         
       ) t
    CROSS JOIN (SELECT FLOOR(RAND()*100) AS rn) AS s
    WHERE t.rn IS NULL

)
SELECT rn
FROM CTE
Run Code Online (Sandbox Code Playgroud)

编辑:

正如下面的评论中所述,上面的方法不起作用:如果第一个生成的数字(来自锚成员)是已经存在于 中的CTE数字,则递归成员的 将返回,因此将返回来自锚成员的数字。randomNumsCROSS JOINNULL

这是一个不同的版本,基于使用递归的相同想法CTE,可以工作:

DECLARE @maxAttempts INT = 100

;WITH CTE AS
(
   SELECT FLOOR(RAND()*100) AS rn,  
          1 AS i 

   UNION ALL

   SELECT FLOOR(RAND(CHECKSUM(NEWID()))*100) AS rn, i = i + 1
   FROM CTE AS c
   INNER JOIN randomNums AS r ON c.rn = r.num   
   WHERE (i = i) AND (i < @maxAttempts) 
)
SELECT TOP 1 rn
FROM CTE
ORDER BY i DESC
Run Code Online (Sandbox Code Playgroud)

这里,锚定成员首先CTE生成随机数。如果该数字已经存在于递归成员中randomNumsINNER JOIN则递归成员将成功,因此将生成另一个随机数。否则,INNER JOIN将失败并且递归将终止。

还有几点需要注意:

  • i变量用于记录生成“唯一”随机数的尝试次数。
  • 的值i用于INNER JOIN递归成员的运算,以便仅与前一个递归的随机值相连接。
  • 由于使用相同的种子值重复调用RAND()会返回相同的结果,因此我们必须使用CHECKSUM(NEWID())的种子RAND()
  • @maxAttempts可以选择用于指定生成“唯一”随机数的最大尝试次数。

SQL Fiddle 演示在这里