据我所知,在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};
答案 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)
计划
答案 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;