在查看代码时,我遇到了一些奇怪的事情,有人读过你可以使用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(这是程序员在编写代码时使用的'测试')
从这一切开始,我怀疑这是因为它被重新执行每次比较而不是每一行,有人可以确认这一点,并提供一个很好的链接来解释这种行为,以便我可以指出它吗?
答案 0 :(得分:2)
为什么,这是预期的。
对ABS(CHECKSUM(NewId())) % 3 + 1
中的每一行评估 @Values
一次,因此每行的值都不同。
因此它可以返回多行,或者根本不返回任何行。
这正是你在说的时候应该期待的,这个表达式会计算每一行。
显然你真正想要的是一个每个查询评估一次的表达式。
答案 1 :(得分:0)
newID将始终每行调用一次,如果您需要使用类似的唯一值:
ROUND(((3) * RAND() + 1), 0)