Какие джойны и группировки используются для подсчета количества людей по адресам
Что проверяют
Умеете ли вы выбрать правильный тип соединения под задачу и не ошибиться с COUNT. Главная ловушка: адреса, где никто не живёт, должны попасть в результат с нулём. Следом обычно просят оставить только адреса с несколькими жильцами и спрашивают, как прочитать результат в Go.
Как отвечать
Схема обычно такая: addresses(id, street) и people(id, address_id). Если нужны все адреса, включая пустые, таблица адресов стоит слева:
SELECT a.id, a.street, COUNT(p.id) AS people_count
FROM addresses a
LEFT JOIN people p ON p.address_id = a.id
GROUP BY a.id, a.street
ORDER BY people_count DESC;Что здесь важно:
LEFT JOINот адресов: сохраняет адреса без людей.INNER JOINих выбросит, и это нормально, только если пустые адреса не нужны;- *
COUNT(p.id), а не `COUNT()**: для пустого адреса соединение даёт одну строку сNULLв колонках людей.COUNT(*)посчитает её как единицу,COUNT(p.id)` даст ноль; - группировка по ключу: группируйте по
a.id, а не по тексту адреса, иначе разные адреса с одинаковой записью склеятся; HAVING COUNT(p.id) > 1: фильтр по результату агрегата,WHEREтут не подходит;- связь многие ко многим: если человек привязан к адресам через промежуточную таблицу, считайте
COUNT(DISTINCT person_id).
Для производительности нужен индекс по people.address_id. В Go результат читается через rows.Scan, счётчик из COUNT удобнее класть в int64, закрыть выборку через defer rows.Close() и после цикла обязательно проверить rows.Err().
Где спотыкаются
Ставят LEFT JOIN не с той стороны: FROM people LEFT JOIN addresses сохраняет людей без адреса, а пустые адреса как раз теряет.
Считают COUNT(*) и получают единицу вместо нуля у пустых адресов.
Добавляют условие на правую таблицу в WHERE, например WHERE p.age > 18. Строки с NULL отсекаются, и LEFT JOIN молча превращается во внутреннее соединение. Такое условие нужно переносить в ON.