Почему в SQL запросе используется группировка по id пользователя и можно ли группировать только по id?
Что проверяют
Знаете ли вы правило выбора колонок при группировке и понимаете ли, что оно зависит от СУБД. Для питониста тут есть и второй слой: считаете вы агрегаты запросом или тянете все строки в память и складываете их сами.
Как отвечать
GROUP BY схлопывает строки в группы, и в списке выборки допустимы только колонки группировки и агрегаты. Группировка по идентификатору пользователя означает одну строку на пользователя, а COUNT, SUM и AVG считаются внутри его строк.
Можно ли группировать только по идентификатору, зависит от базы:
- PostgreSQL разрешает выбрать и остальные колонки той же таблицы, если группировка идёт по её первичному ключу: имя функционально зависит от ключа, и однозначность доказуема;
- MySQL с включённым
ONLY_FULL_GROUP_BYведёт себя так же, а с выключенным молча берёт произвольное значение из группы; - SQLite это ограничение не проверяет вовсе.
SELECT u.id, u.name, COUNT(o.id) AS orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id;Стоит добавить, что фильтр по агрегату это HAVING, а WHERE отрабатывает до группировки. В Python то же самое пишется через ORM вызовом group_by с func.count, либо оконными функциями, если в ответе нужны и детальные строки, и итог по пользователю. Выгружать строки ради groupby в pandas оправдано, только когда данных заведомо мало.
Где спотыкаются
Пишут COUNT(*) вместе с внешним соединением. Пользователь без заказов всё равно даёт строку, где правая часть пустая, и такая строка посчитается за единицу. Считать надо колонку правой таблицы, COUNT(o.id) пропускает пустые значения и честно возвращает ноль.
Второе: группируют по имени вместо идентификатора. Полные тёзки склеиваются в одну строку, и на тестовых данных это незаметно, а на боевых совпадения находятся обязательно.
Третье: собирают несколько агрегатов по разным связям в одном запросе. Два соединения, с заказами и с платежами, размножают строки, и суммы удваиваются. Лечится подзапросами, боковым соединением или COUNT(DISTINCT ...).