Объяснение возвращаемого значения COUNT при использовании без группы - PullRequest
5 голосов
/ 22 марта 2020

COUNT возвращает количество элементов, найденных в группе, и по умолчанию оно содержит значения NULL и дубликаты.

Первые два оператора возвращают ошибку, а вторые два - NULL:

1/0
1/'A'
1/NULL
NULL/1

Но в COUNT они возвращают 1 и 0:

SELECT COUNT(1/0);    -- 1
SELECT COUNT(1/'A');  -- 1
SELECT COUNT(1/NULL); -- 0
SELECT COUNT(NULL/1); -- 0

Случаи NULL могут быть объяснены документами как

COUNT (выражение ALL) вычисляет выражение для каждой строки в группе и возвращает число ненулевых значений.

Итак, они оцениваются, они возвращают NULL с, а поскольку non null значения являются только счетчиками, мы получаем 0.

Мне интересно, почему первые два возвращаются 1?

Имея значения в таблице, все кажется нормальным - выдается ошибка и значение не возвращается:

DECLARE @DataSource TABLE
(
    [valueA] INT
   ,[valueB] INT
);

INSERT INTO @DataSource ([valueA],[valueB])
VALUES (1, 0);

SELECT COUNT([valueA]/[valueB])
FROM @DataSource;

(затронуто 1 строка) Msg 8134, уровень 16, состояние 1, строка 16 Обнаружена ошибка деления на ноль.

Время завершения: 2020-03-22T13: 47: 44.5512536 + 02: 00

Возможно, это 1 row affected возвращается как COUNT

Ответы [ 2 ]

4 голосов
/ 22 марта 2020

Если в выражении COUNT указаны константы, SQL Сервер может оптимизировать запрос во время компиляции, избегая оценки выражения во время выполнения. Результирующее значение никогда не может быть NULL в первых 2 запросах и всегда будет NULL в последних 2 запросах.

Ниже приведен фрагмент из планов выполнения SELECT COUNT(1/0) и SELECT COUNT(1/NULL):

<ScalarOperator ScalarString="Count(*)">
<Const ConstValue="NULL" />

Сообщение "1 строка затронута", сгенерированное клиентским инструментом (SSMS), отражающее количество строк, возвращенное оператором INSERT. Если нежелательно, добавьте SET NOCOUNT ON; в начало скрипта.

3 голосов
/ 22 марта 2020

Как вы можете видеть в документах, которые вы копировали далее, COUNT(<expression>) учитывает каждое ненулевое значение. Если вы хотите сосчитать все записи в группе, независимо от значения того или иного столбца, вам нужно COUNT(*) (или другие эквивалентные выражения, например COUNT(1)).

Выражение в COUNT() вычисляется для каждой строки; если возникает ошибка, то весь запрос ошибок. Я бы посчитал SELECT COUNT(1/0) возврат 1 нелогичным поведением, возможно, из-за преждевременной оптимизации (SELECT 1/0 делает ошибку).

Но в реальной ситуации, как в вашем сценарии, вы можно увидеть, что возникает ошибка :

Ошибка деления на ноль.

Редактировать - проверка этого на другом базы данных не показывают согласованности в результатах:

  • In MySQL, MariaDB 10.4 и SQLite: SELECT COUNT(1/0) возвращает 0

  • В Postgres: ERROR: division by zero

  • В Oracle: ORA-01476: divisor is equal to zero

  • В DB2: возвращается 1

...