В PostgreSQL нужно посчитать сумму продаж только по активным клиентам, при этом не исключая остальных клиентов из итоговой выборки. Какой синтаксис подойдёт?
GROUP BY, HAVING, COUNT, SUM, AVG — агрегатные функции встречаются практически в каждой SQL-задаче на собеседовании. Интервьюеры проверяют, понимаете ли вы разницу между WHERE и HAVING, умеете ли группировать по нескольким полям и фильтровать по результатам агрегации. Без уверенного владения этим блоком невозможно решить ни одну аналитическую задачу на SQL.
Всего в этом разделе 32 вопросов. Каждый — с правильным ответом и кратким разбором теории. Разбито на 7 частей по 5 вопросов.
1В таблице пользователей есть колонка `middle_name`, в которой часто хранится `NULL`. Что вернёт выражение `COUNT(middle_name)`?
AЧисло всех строк таблицы, включая те, где значение колонки равно `NULL`
BЧисло строк, в которых значение колонки `middle_name` не равно `NULL`
CЗначение `NULL`, если в колонке `middle_name` встречается хотя бы одно `NULL`
DНоль для любой колонки, в которой есть хотя бы одно значение `NULL`
Ответ: `COUNT(колонка)` считает только строки с не-`NULL` значением в этой колонке.
Агрегат `COUNT(колонка)` пропускает строки, где значение этой колонки равно `NULL`, и считает только заполненные. Чтобы получить количество всех строк независимо от пропусков, используют `COUNT(*)`. Поэтому разница между `COUNT(*)` и `COUNT(middle_name)` показывает, сколько пользователей не указали отчество. Это базовое поведение полезно помнить при подсчёте конверсий по необязательным полям.
2Есть таблица `payments(amount)`, в части строк `amount` равно `NULL`. Какой запрос посчитает количество всех строк в таблице, включая строки с `NULL` в столбце `amount`?
A`SELECT COUNT(amount) FROM payments;`: счёт пропустит строки, где значение `amount` равно `NULL`
B`SELECT COUNT(amount) FROM payments WHERE amount IS NOT NULL;`: фильтр и `COUNT(amount)` оба исключают `NULL`
C`SELECT COUNT(*) FROM payments;`: счёт всех строк таблицы, включая строки со значением `NULL` в `amount`
D`SELECT COUNT(*) FROM payments WHERE amount IS NOT NULL;`: фильтр уберёт строки с `NULL` ещё до подсчёта
Ответ: `COUNT(*)` считает все строки, а `COUNT(колонка)` — только строки, где колонка не равна `NULL`.
Выражение `COUNT(*)` не зависит от значений конкретных колонок и считает все строки, включая те, где `NULL` встречается в каких-то полях. В отличие от него `COUNT(amount)` игнорирует строки, где `amount` равно `NULL`. Дополнительный фильтр `WHERE amount IS NOT NULL` уберёт такие строки и до `COUNT(*)`, поэтому результат уже не будет включать `NULL`-строки.
3Что вернёт запрос `SELECT AVG(salary) FROM employees;`?
AОдна строка с одной колонкой: среднее `salary` по всей таблице `employees`
BПо одной строке на каждого сотрудника со значением поля `salary` без агрегации
CПо одной строке на каждый отдел со средней зарплатой внутри этого отдела
DОшибка выполнения: агрегат `AVG` без `GROUP BY` в SQL не разрешён
Ответ: Агрегат без `GROUP BY` возвращает одну строку по всей выборке.
Если в запросе используется агрегатная функция, например `AVG(salary)`, и нет `GROUP BY`, то результатом будет одна строка с агрегированным значением по всем выбранным строкам. В примере это средняя зарплата по всем сотрудникам в таблице `employees`. Возврат строки на сотрудника требовал бы отказа от агрегата; группировка по отделам — добавления `GROUP BY department`; ошибки тут не будет, потому что без `GROUP BY` агрегат корректен.
4Что делает оператор `HAVING` в SQL-запросе с группировкой?
AФильтрует строки до агрегации, как `WHERE`, и не работает с результатами `COUNT` или `SUM`
BФильтрует группы после `GROUP BY` и применяется к результатам агрегатов, например `COUNT` или `SUM`
CСортирует результаты группировки, как `ORDER BY`, по значениям агрегатных функций
DСчитает агрегаты по группам, как `COUNT` или `SUM`, и не выполняет фильтрацию данных
Ответ: `HAVING` фильтрует уже агрегированные группы, в отличие от `WHERE`, который фильтрует строки до агрегации.
`WHERE` применяется до агрегации и фильтрует строки, а `HAVING` — после `GROUP BY` и фильтрует группы по значениям агрегатов. Пример: `SELECT dept, COUNT(*) FROM users GROUP BY dept HAVING COUNT(*) > 5;`. Сортировкой занимается `ORDER BY`, а сами агрегаты считают функции вроде `COUNT` или `SUM` — это разные роли в запросе.
5Что делает оператор `DISTINCT` в `SELECT`-запросе?
AСортирует строки по выбранным столбцам и возвращает их в упорядоченном виде
BУдаляет строки, в которых все выбранные столбцы содержат `NULL`-значения
CУбирает повторяющиеся строки из результата по набору выбранных столбцов
DГруппирует строки по выбранным столбцам и считает по ним агрегаты
Ответ: `DISTINCT` оставляет только уникальные комбинации выбранных столбцов в результате запроса.
`DISTINCT` применяется ко всем выбранным колонкам и оставляет в результате только уникальные комбинации значений. Часто эквивалентен `GROUP BY` по тем же колонкам, если не используются агрегаты. Сортировку он не выполняет — порядок строк не гарантирован, для него нужен `ORDER BY`. И `NULL` он не удаляет: повторяющиеся `NULL` сворачиваются в одну строку, как и любые другие повторы.