【发布时间】:2012-02-27 11:06:45
【问题描述】:
在查看代码时,我遇到了一些奇怪的事情,有人读到您可以使用 ABS(CHECKSUM(NewId())) % N 来获取从 0 到 N-1 的随机数(因为 RAND() 不会每行出现),但我怀疑他们并没有真正测试他们的代码(现在用表变量简化了,实际代码做了一个TOP 1 country 来错误地解决下面的问题):
DECLARE @Values TABLE
(
id int identity,
country VARCHAR(100)
)
INSERT INTO @Values (country) VALUES ('UK'), ('USA'), ('China')
SELECT *, (SELECT country FROM @Values v WHERE v.id = ABS(CHECKSUM(NewId())) % 3 + 1)
FROM @Values
执行时出现以下错误:
子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。
我的第一个问题是子查询如何返回多个值?为什么有时它根本没有返回值? (注意 不是我在 SO 提出的问题)测试者:
SELECT country FROM @Values v WHERE v.id = ABS(CHECKSUM(NewId())) % 3 + 1
但无论执行多少次:
SELECT ABS(CHECKSUM(NewId())) % 3 + 1
返回的结果总是 1,2,3(这是程序员在编写代码时使用的“测试”)
从这一切来看,我怀疑这是因为每次比较而不是每一行都重新执行它,有人可以确认这一点并提供一个很好的链接来解释这种行为,以便我可以向他指出吗?
【问题讨论】:
-
我不明白你在说什么。您是说他们选择校验和路由是因为
RAND没有按行评估,现在您要问为什么它按行评估? -
@LasseV.Karlsen - 看起来他们需要每个外部查询行评估一次但在传递到子查询时稳定的东西。
SELECT *, (SELECT country FROM @Values v WHERE v.id = CA.id) FROM @Values CROSS APPLY (SELECT ABS(CHECKSUM(NewId())) % 3 + 1) CA(id)会这样做,但不保证会这样做。 -
@MartinSmith 如果您将其发布为答案,我会接受。
-
SELECT *, (SELECT country FROM @Values v WHERE v.id = CA.id) FROM @Values CROSS JOIN (SELECT ABS(CHECKSUM(NewId())) % 3 + 1) CA(id)也可以工作(可能与 CROSS APPLY 一样(非)可靠)。
标签: sql sql-server random newid