COUNT(*) против COUNT(col) против COUNT(DISTINCT)
Три разных COUNT, которые путают на собеседованиях: COUNT(*), COUNT(col) и COUNT(DISTINCT col).
COUNT(*)считает строки,COUNT(col)— ненулевые значения колонки,COUNT(DISTINCT col)— уникальные ненулевые значения.
В чём разница
Ключевое отличие — отношение к NULL. COUNT(*) считает все строки подряд. COUNT(col) пропускает строки, где col равен NULL. COUNT(DISTINCT col) вдобавок схлопывает одинаковые значения.
CREATE TABLE feedback (
id INTEGER PRIMARY KEY,
user TEXT,
rating INTEGER -- может быть NULL, если оценку не поставили
);
INSERT INTO feedback (user, rating) VALUES
('Аня', 5),
('Борис', 5),
('Вера', NULL), -- нет оценки
('Гена', 3),
('Дина', NULL); -- нет оценки
SELECT
COUNT(*) AS vsego_strok, -- 5
COUNT(rating) AS s_ocenkoy, -- 3 (NULL не считаются)
COUNT(DISTINCT rating) AS unikalnyh_ocenok -- 2 (значения 5 и 3)
FROM feedback;
Вывод:
5|3|2
Всего 5 строк. С оценкой — только 3 (две NULL отброшены). Уникальных оценок — 2: значения 5 и 3 (повтор пятёрки схлопнут, NULL не считаются).
Практический вывод
Когда нужно «сколько всего записей» — берите COUNT(*). Когда «у скольких заполнено поле» — COUNT(col). Когда «сколько разных значений» — COUNT(DISTINCT col). Путаница тут приводит к неверной аналитике.
COUNT в связке с LEFT JOIN
Тонкость: после LEFT JOIN у клиентов без заказов правые колонки — NULL. Если посчитать COUNT(*), такой клиент получит 1 (строка-то есть). А правильно — COUNT(o.id), который даст 0, потому что o.id там NULL.
CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO customers (id, name) VALUES (1,'Аня'), (2,'Вера');
CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER);
INSERT INTO orders (customer_id) VALUES (1), (1);
SELECT c.name,
COUNT(*) AS count_zvezda, -- у Веры будет 1 (ловушка!)
COUNT(o.id) AS count_zakazov -- у Веры честный 0
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name
ORDER BY c.name;
Вывод:
Аня|2|2 Вера|1|0
У Веры count_zvezda = 1 (строка от LEFT JOIN есть), но count_zakazov = 0 — заказов реально нет. После LEFT JOIN всегда считайте COUNT(колонка_правой_таблицы), а не COUNT(*).
Итог
COUNT(*)— все строки;COUNT(col)— без NULL;COUNT(DISTINCT col)— уникальные без NULL.- После
LEFT JOINсчитайтеCOUNT(колонка_правой_таблицы), иначе клиенты без пар получат лишнюю единицу. - Выбор COUNT влияет на цифры в отчётах — не путайте смыслы.