SQL Server:WHERE子句中的随机数

时间:2017-07-12 10:37:54

标签: sql-server select random

据我所知,在SELECT语句中获取随机值的唯一方法是使用newid()函数,因为random()函数不会生成新的每行的值。

这会导致以下尴尬的构造,从0到9获得一个随机数:

abs(checksum(newid())) % 10

如果我在SELECT子句中使用此表达式,它的行为与预期的一样。但是,如果我尝试以下内容:

select *
from table
where abs(checksum(newid())) % 10>4;

我应该知道我会得到大约一半的行。相反,我得到了全部或全部。显然newid()仅评估一次,而不是每行。

问题是,如何在WHERE子句中使用随机数?

更多

有一个类似的问题是随机要求固定行数。在上面的例子中我可以使用:

select top 50 percent from table order by newid();

这将得到我想要的东西。

问题仍然存在,如何在WHERE子句中使用随机数。例如,是否可以做这样的事情?

select *
from table
where code={random number};

3 个答案:

答案 0 :(得分:0)

以下是解决问题的一种方法

SELECT *
FROM   (SELECT *,
               Abs(Checksum(Newid())) % 10 AS ran
        FROM   yourtable) a
WHERE  ran > 4; 

由于newid()子句中where因某种原因,它只执行一次,并使用常量进行检查。

当我检查执行计划时,您的查询缺失compute scalar,因为我的查询在执行计划中存在计算标量。

答案 1 :(得分:0)

  

我应该知道我会得到大约一半的行。相反,我得到了全部或全部

你可能得到所有的行或者没有它们,因为当你在where子句中使用它时,每个查询执行一次NEWID()。这在Conor Cunnigham这里解释,其技术术语称为{{ 3}}

您可以查看执行计划并留意以下表达

  

Const ConstValue

你可以看到计算一次并在整个过程中使用,最后你只是做一个布尔比较,所以你最终会得到所有行或没有

你必须使用CTE,就像在另一个答案中陈述的那样,或者使用Top with new order by newid()或tablesample来返回随机行

您可能会发现Tablesample选项更有帮助,因为这可能不会通过所有表数据来获取行样本集,这与Newid()

不同 下面的

是具有1000000行的表的一个例子

select *  from Orders
TABLESAMPLE (50 PERCENT)

计划

RumTimeConstants

答案 2 :(得分:0)

函数newid()WHERE子句中仅计算一次,而不是逐行计算。诀窍是迫使它逐行运行。

当然,可以将其包含在SELECT子句中,然后根据其他答案将其包含在CTE或子查询中。

Microsoft在此处提供了一种解决方案:https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms189108(v=sql.105)?redirectedfrom=MSDN

诀窍是通过将newid()与某些行值组合来强制进行重新计算。在checksum()函数中很容易做到这一点。

例如:

SELECT *
FROM table
WHERE abs(checksum(newid(),id)) % 10>4;