سؤال

When reviewing code I came across something odd, someone had read that you can use ABS(CHECKSUM(NewId())) % N to get you random numbers from 0 to N-1 (as RAND() doesn't occur per-row), but I suspect they didn't really test their code (simplified down now with table variables, and actual code did a TOP 1 country to incorrectly get around a problem below):

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

When executed the following error occurs:

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

My first question was how can the subquery return more than one value? and how is it that it some times returns no value at all? (Note not the question that I'm asking at SO) Tested by:

SELECT country FROM @Values v WHERE v.id = ABS(CHECKSUM(NewId())) % 3 + 1

Yet no matter how many times the following is executed:

SELECT ABS(CHECKSUM(NewId())) % 3 + 1

The returned results are always 1,2,3 (this was the 'testing' the programmer had used when writing their code)

From all this, I suspect this is because it's being re-executed for every compare and not every row, can someone confirm this and provide a good link to explain this behaviour so that I can point it out to him?

هل كانت مفيدة؟

المحلول

Why, this is expected.

ABS(CHECKSUM(NewId())) % 3 + 1 is evaluated once for each row in @Values, and therefore has different values for each row.

So it can return multiple rows, or no rows at all.

This is exactly what you should be expecting when saying, This expression evaluates for every row.

Apparently what you actually want is an expression that evaluates once per query.

نصائح أخرى

newID will always be called once per row, if you need a unique value use something like:

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top