Какие условия заставляют CHECKSUM_AGG возвращать 0?

Похоже, что существует ряд условий, которые заставляют CHECKSUM_AGG возвращать 0, которых я бы не ожидал. Мне удалось найти только один обсуждаемый вопрос, который приведет к его дублированию. Это можно решить с помощью DISTINCT или GROUP BY.

Я также нашел еще несколько сценариев, которые имеют меньше смысла для меня. Один из них был предоставлен моим начальником, и я нашел MSDN. Это я не знаю, как объяснить. Вот несколько SQL, которые демонстрируют сценарии:

SELECT
    CHECKSUM_AGG(T.Number) AS ChecksumAgggregate
FROM
(
    VALUES
        (2)
        , (3)
        , (4)
        , (5)
)AS T(Number)

DECLARE @t TABLE 
(
    Category VARCHAR(15),
    Value VARCHAR(10)
)

INSERT @t 
(
    Category
    , Value
)
VALUES 
    ('OneCharacter','a')
    ,('OneCharacter','b')
    ,('OneCharacter','c')
    ,('OneCharacter','d')

    ,('TwoCharacters','aa')
    ,('TwoCharacters','bb')
    ,('TwoCharacters','cc')
    ,('TwoCharacters','dd')

    ,('ThreeCharacters','aaa')
    ,('ThreeCharacters','bbb')
    ,('ThreeCharacters','ccc')
    ,('ThreeCharacters','ddd')

    ,('SixCharacters','aaaaaa')
    ,('SixCharacters','bbbbbb')
    ,('SixCharacters','cccccc')
    ,('SixCharacters','dddddd')

    ,('AllValues','a')
    ,('AllValues','b')
    ,('AllValues','c')
    ,('AllValues','d')
    ,('AllValues','aa')
    ,('AllValues','bb')
    ,('AllValues','cc')
    ,('AllValues','dd')
    ,('AllValues','aaa')
    ,('AllValues','bbb')
    ,('AllValues','ccc')
    ,('AllValues','ddd')
    ,('AllValues','aaaaaa')
    ,('AllValues','bbbbbb')
    ,('AllValues','cccccc')
    ,('AllValues','dddddd')

select 
    Category, CHECKSUM_AGG(CHECKSUM(Value)) 
from @t 
group by Category

select Category, Value, CHECKSUM(Value) ValueChecksum
from @t

В этих примерах из CHECKSUM_AGG из этих запросов нет ничего, кроме 0. Последний запрос показывает, что ни один из значений CHECKSUM, входящих в вызов CHECKSUM_AGG, не дублируется.

Я надеюсь, что любой ответ описывает, какие причины CHECKSUM_AGG для возврата 0 также объяснят эти ситуации.

Ответ 1

Это может произойти, если, например, существует четное количество строк, или если значения суммируются до определенных значений (например, 14). Оба они дают 0:

SELECT CHECKSUM_AGG(N)
FROM (VALUES (1),(2),(3),(4),(4)) AS T(N);

SELECT CHECKSUM_AGG(N)
FROM (VALUES (2),(3),(4),(5)) AS T(N);

Но это не так:

SELECT CHECKSUM_AGG(N)
FROM (VALUES (1),(2),(3),(4),(5)) AS T(N);

SELECT CHECKSUM_AGG(N)
FROM (VALUES (2),(3),(4),(6)) AS T(N);

14 может быть просто совпадением (и этого не происходит для этого значения через 6 строк), я упоминаю это только потому, что это единственный шаблон, который я заметил здесь. Я не знаю, что любой из этих случаев документирован.

Также вы знаете, что CHECKSUM_AGG официально задокументирован как ненадежный, то есть может неточно отражать изменение данных, правильно? Док не вникает в подробности об этом, он просто утверждает, что иногда он не скажет вам, что произошли изменения, даже если они есть. (Фактическая формулировка: "Однако существует небольшая вероятность того, что контрольная сумма не изменится".)

В любом случае Майкл Сварт, похоже, обнаружил, что CHECKSUM_AGG просто XOR (вот его доказательство):

CREATE TABLE #f(a FLOAT);
GO

INSERT #f VALUES (RAND());
GO 20

DECLARE @i INT = 0;
SELECT @i = @i ^ CHECKSUM(a) FROM #f;
SELECT @i, CHECKSUM_AGG(CHECKSUM(a)) FROM #f;
GO

DROP TABLE #f;
GO

Как он продолжает объяснять, это может привести к вводящим в заблуждение результатам, когда диапазон значений очень мал, так как вероятность создания надежной контрольной суммы быстро уменьшается.