> Какие джойны и группировки используются для подсчета количества людей по адресам (Go)

Уровень: middle · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Wildberries

Стек: Go

> Пример ответа

Короткий ответ

Для подсчёта количества людей по адресам используется LEFT JOIN между таблицами людей и адресов, затем GROUP BY по полям адреса и агрегатная функция COUNT(*) или COUNT(people.id). Если нужно учитывать только людей с адресами - INNER JOIN. В Go обычно это оформляется через SQL-запрос в database/sql или ORM (GORM, sqlx).

Подробное объяснение

Основная задача - связать две сущности: людей (users/people) и адреса (addresses). Связь обычно один-ко-многим: один адрес может принадлежать нескольким людям (например, семья), либо один человек имеет один адрес (один-к-одному). В зависимости от модели данных выбирается тип join:

  • INNER JOIN - вернёт только те записи, где есть соответствие в обеих таблицах. Подходит, если нужно считать только людей с заполненными адресами.
  • LEFT JOIN - вернёт всех людей, даже без адреса (тогда адресные поля будут NULL). При подсчёте через COUNT(people.id) такие записи не потеряются, но если считать COUNT(addresses.id) - они не попадут в результат.
  • RIGHT JOIN - используется редко, если нужно гарантированно вывести все адреса, даже без людей.

Группировка выполняется по полям, которые определяют уникальность адреса: city, street, house, apartment - в зависимости от структуры. Если адрес хранится одной строкой - группировка по ней.

Важно: при использовании GROUP BY все неагрегированные поля в SELECT должны быть включены в GROUP BY. Иначе SQLite/PostgreSQL/MySQL выдадут ошибку или непредсказуемый результат.

На практике

В Go запрос обычно выполняется через database/sql с подготовленными statements. Если используется GORM, можно построить запрос через цепочку методов: Model(&User{}).Select("addresses.city, COUNT(*) as cnt").Joins("LEFT JOIN addresses ON ...").Group("addresses.city").

Для больших таблиц стоит добавить индексы на внешний ключ (address_id в таблице людей) и на поля группировки. Также полезно использовать COUNT(DISTINCT ...), если нужно исключить дубликаты.

Пример кода

GO
type AddressCount struct {
City string
Count int
}
func CountPeopleByCity(db *sql.DB) ([]AddressCount, error) {
query := `
SELECT a.city, COUNT(p.id) as cnt
FROM people p
LEFT JOIN addresses a ON p.address_id = a.id
GROUP BY a.city
ORDER BY cnt DESC
`
rows, err := db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
var result []AddressCount
for rows.Next() {
var ac AddressCount
if err := rows.Scan(&ac.City, &ac.Count); err != nil {
return nil, err
}
result = append(result, ac)
}
return result, rows.Err()
}

Как отвечать на собеседовании

Начни с уточнения модели данных: связь между таблицами, наличие внешних ключей. Затем опиши выбор join в зависимости от бизнес-требований: нужны ли люди без адресов. Обязательно упомяни группировку и агрегацию, а также нюанс с COUNT(*) vs COUNT(column) - второй вариант игнорирует NULL. Покажи понимание, что в Go это просто строка SQL, и приведи пример с database/sql или ORM. Если спросят про производительность - упомяни индексы и EXPLAIN.

Что проверяет интервьюер

  • Понимание типов join и их различий.
  • Умение корректно использовать GROUP BY с агрегатными функциями.
  • Знание особенностей COUNT с NULL.
  • Практический опыт написания SQL-запросов в Go.
  • Понимание модели данных и связей между таблицами.

Типичные ошибки

  • Использование COUNT(*) при LEFT JOIN - посчитает и людей без адресов, но если в SELECT есть поля адреса, они будут NULL, и группировка по ним создаст отдельную группу с NULL.
  • Забывают включить все неагрегированные поля в GROUP BY.
  • Путают LEFT JOIN и INNER JOIN при подсчёте - результат может отличаться.
  • Не учитывают, что COUNT(addresses.id) при LEFT JOIN вернёт 0 для людей без адреса, а COUNT(people.id) - 1.
  • В Go забывают закрывать rows через defer rows.Close() или не проверяют rows.Err() после итерации.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью