2

在查看代码时,我遇到了一些奇怪的事情,有人读到您可以使用它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(这是程序员在编写代码时使用的“测试”)

从这一切来看,我怀疑这是因为每次比较而不是每一行都重新执行它,有人可以确认这一点并提供一个很好的链接来解释这种行为,以便我可以向他指出吗?

4

2 回答 2

2

为什么,这是意料之中的。

ABS(CHECKSUM(NewId())) % 3 + 1对 中的每一行计算一次@Values,因此每一行都有不同的值。

所以它可以返回多行,或者根本没有行。

这正是您在说此表达式时应该对每一行进行评估时所期望的。

显然,您真正想要的是每个查询计算一次的表达式。

于 2012-02-27T11:13:31.000 回答
0

newID 将始终每行调用一次,如果您需要唯一值,请使用以下内容:

ROUND(((3) * RAND() + 1), 0)

于 2012-02-27T12:41:29.440 回答