Зачем мне нужно "OR NULL" в MySQL при подсчете строк с условием - PullRequest
5 голосов
/ 16 февраля 2011

Есть вопрос об агрегатной функции MySQL COUNT (), которая время от времени всплывает в моей голове. Я хотел бы получить некоторое объяснение того, почему это работает так, как есть.

Когда я начал работать с MySQL, я быстро понял, что его COUNT (условие), кажется, работает правильно только в том случае, если условие также содержит OR NULL в конце. В случае более сложных условий COUNT это был эмпирический процесс, чтобы выяснить, где именно это поставить. В MSSQL вам не нужен этот OR NULL для получения правильных результатов, поэтому я хотел бы узнать его объяснение. Итак, вот пример.

Давайте иметь очень простую таблицу со следующей структурой и данными:

CREATE TABLE test (
  `value` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO test (value) VALUES(1);
INSERT INTO test (value) VALUES(4);
INSERT INTO test (value) VALUES(5);
INSERT INTO test (value) VALUES(6);
INSERT INTO test (value) VALUES(4);
INSERT INTO test (value) VALUES(4);
INSERT INTO test (value) VALUES(5);
INSERT INTO test (value) VALUES(2);
INSERT INTO test (value) VALUES(8);
INSERT INTO test (value) VALUES(1);

Сценарий: я хотел бы посчитать, сколько строк у меня есть, где значение = 4. Очевидным решением было бы отфильтровать его с помощью WHERE и выполнить COUNT (*), но меня интересует COUNT (условие) решение на основе

Итак, решение, которое приходит мне в голову:

SELECT COUNT(value=4) 
  FROM test

Результат 10. Это явно неправильно.

Вторая попытка с OR NULL:

SELECT COUNT(value=4 OR NULL) 
  FROM test

Результат 3. Это правильно.

Может кто-нибудь объяснить логику этого? Это какая-то ошибка в MySQL или есть логическое объяснение, почему мне нужно добавить этот странно выглядящий OR NULL в конец условия COUNT, чтобы получить правильный результат?

Ответы [ 5 ]

12 голосов
/ 16 февраля 2011

Это должно раскрыть все

SELECT 4=4, 3=4, 1 or null, 0 or null

Вывод

1   |   0   |   1   |   NULL

Факты

  1. COUNT добавляет столбцы / выражения, которые оцениваются как NOTНОЛЬ.Все будет увеличиваться на 1, пока оно не равно нулю.Исключением является COUNT (DISTINCT), где оно увеличивается, только если оно еще не подсчитано.

  2. Когда выражение BOOLEAN используется само по себе, оно возвращает либо 1, либо 0.

  3. Когда логическое значение OR имеет значение NULL, оно равно NULL только тогда, когда оно равно 0 (ложно)

Для других

Да, если счетчик является ТОЛЬКО желаемым столбцом, можно использовать WHERE value=4, но если это запрос, который хочет подсчитать 4 , а также , получая другие значения / агрегаты,тогда фильтр не работает.Альтернативой было бы SUM(value=4), например

SELECT sum(value=4)
  FROM test
5 голосов
/ 16 февраля 2011

COUNT() функция принимает аргумент, который обрабатывается как NULL или NOT NULL.Если это NOT NULL - тогда оно увеличивает значение и ничего не делает иначе.

В вашем случае выражение value=4 равно TRUE или FALSE, очевидно, что оба true иfalse не равны нулю, поэтому вы получаете 10.

, но меня интересует решение на основе COUNT (условие).

Решение на основе count всегда будет медленнее (намного медленнее), поскольку оно приведет к полному сканированию таблицы и итеративному сравнению каждого значения.

3 голосов
/ 16 февраля 2011

COUNT(expression) подсчитывает количество строк, для которых выражение не равно NULL.Выражение value=4 имеет значение только NULL, если значение равно NULL, в противном случае это либо TRUE (1), либо FALSE (0), которые подсчитываются.

1 = 4         | FALSE
4 = 4         | TRUE
1 = 4 OR NULL | NULL
4 = 4 OR NULL | TRUE

Вместо этого можно использовать SUM:

SELECT SUM(value=4) FROM test

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

SELECT
    SUM(a>b) AS foo,
    SUM(b>c) AS bar,
    COUNT(*) AS total_rows
FROM test
0 голосов
/ 16 февраля 2011

Это потому, что COUNT (выражение) считает значения. В теории SQL NULL является СОСТОЯНИЕМ, а не ЗНАЧЕНИЕМ, и поэтому не учитывается. NULL - это состояние, означающее, что значение поля неизвестно.

Теперь, когда вы пишете «значение = 4», это дает булево значение ИСТИНА или ЛОЖЬ. Поскольку TRUE и FALSE являются ЗНАЧЕНИЯМИ, результат равен 10.

Когда вы добавляете «ИЛИ НУЛЬ», у вас фактически есть «ИСТИНА ИЛИ НУЛЬ» и «ЛОЖЬ ИЛИ НУЛЬ». Теперь «TRUE OR NULL» оценивается как TRUE, а «FALSE OR NULL» - в NULL. Таким образом, результат равен 3, потому что у вас есть только 3 значения (и семь состояний NULL).

0 голосов
/ 16 февраля 2011

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

 select count(*)
 from test
 where value = 4

Синтаксис, который вы использовали в варианте Mysql?

...