CHECKSUM (NewId ()) выполняется несколько раз в строке - PullRequest
2 голосов
/ 27 февраля 2012

При просмотре кода я наткнулся на что-то странное, кто-то прочитал, что вы можете использовать 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 (это было «тестирование», которое программист использовал при написании своего кода)

Из всего этого, я подозреваю, это потому, что оно выполняется повторно для каждого сравненияи не в каждой строке, кто-то может подтвердить это и дать хорошую ссылку, чтобы объяснить это поведение, чтобы я мог указать ему на это?

Ответы [ 2 ]

2 голосов
/ 27 февраля 2012

Почему, это ожидаемо.

ABS(CHECKSUM(NewId())) % 3 + 1 вычисляется один раз для каждой строки в @Values и поэтому имеет разные значения для каждой строки.

Таким образом, он может возвращать несколько строкили вообще без строк.

Это именно то, что вы должны ожидать, когда говорите: «Это выражение вычисляется для каждой строки.

Очевидно, что вам действительно нужно выражение, которое оценивается один раз для запроса.

0 голосов
/ 27 февраля 2012

newID всегда будет вызываться один раз в строке, если вам нужно уникальное значение, используйте что-то вроде:

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

...