> Как исправить SQL запрос, который собирает строку без контекста? (Go)

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

Компании: InDrive

Стек: Go

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

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

Проблема в том, что SQL-запрос собирает строку без контекста - значит, данные теряют связь с сущностью, к которой относятся. Исправление: добавить в запрос контекстные поля (например, user_id, order_id) через JOIN или подзапрос, либо использовать GROUP_CONCAT с ORDER BY и группировкой. В Go это часто решается через JOIN и сканирование результата в структуру с вложенными полями.

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

Когда запрос собирает строку без контекста, типичная проблема - агрегация без группировки или потеря идентификатора родительской записи. Например:

SQL
SELECT GROUP_CONCAT(name) FROM users;

Возвращает одну строку со всеми именами, но непонятно, к каким заказам или командам они относятся. Исправление - добавить контекст через GROUP BY и включить ключевое поле:

SQL
SELECT department_id, GROUP_CONCAT(name ORDER BY name)
FROM users
GROUP BY department_id;

В Go это означает сканирование результата в структуру с полем DepartmentID и слайсом имён. Если контекст нужен на уровне приложения, можно использовать JOIN для получения связанных данных и группировать уже в коде.

На практике

Для middle-уровня важно показать понимание разницы между исправлением на уровне SQL и на уровне приложения. Если запрос собирает строку без контекста - сначала определи, какой контекст нужен: идентификатор родителя, временной период, статус. Затем выбери:

  • GROUP BY + GROUP_CONCAT - если нужен один уровень агрегации.
  • JOIN + сканирование в структуру - если нужны связанные данные без агрегации.
  • Оконные функции (ROW_NUMBER(), STRING_AGG в PostgreSQL) - если нужен более сложный контекст.

В Go часто проще сделать два запроса и объединить в коде, чем городить сложный SQL.

Пример кода

GO
type UserWithDepartment struct {
DepartmentID int
Names []string
}
// SQL: SELECT department_id, GROUP_CONCAT(name ORDER BY name) FROM users GROUP BY department_id
rows, err := db.Query(`SELECT department_id, GROUP_CONCAT(name ORDER BY name) FROM users GROUP BY department_id`)
if err != nil {
return nil, err
}
defer rows.Close()
var result []UserWithDepartment
for rows.Next() {
var u UserWithDepartment
var names string
if err := rows.Scan(&u.DepartmentID, &names); err != nil {
return nil, err
}
u.Names = strings.Split(names, ",")
result = append(result, u)
}

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

Начни с уточнения: "Что значит без контекста?" - покажи, что анализируешь проблему. Затем объясни, что контекст - это ключевое поле, по которому строки группируются или связываются. Приведи пример с GROUP_CONCAT и GROUP BY. Упомяни trade-off: агрегация в SQL vs группировка в Go. Покажи, что понимаешь, когда лучше вынести логику в приложение (сложные фильтры, пагинация, несколько уровней вложенности).

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

  • Понимание SQL-агрегаций и группировки.
  • Умение видеть потерю контекста в данных.
  • Способность выбрать правильный уровень решения (SQL vs код).
  • Знание Go-паттернов для сканирования агрегированных данных.
  • Умение объяснить trade-off между сложным SQL и дополнительными запросами.

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

  • Предлагать GROUP_CONCAT без GROUP BY - это не исправляет проблему.
  • Сканировать агрегированную строку в плоскую структуру, теряя контекст.
  • Использовать JOIN там, где достаточно GROUP BY, создавая дубликаты строк.
  • Забывать про ORDER BY внутри GROUP_CONCAT - порядок имён становится недетерминированным.
  • Пытаться решить всё одним запросом, когда два простых запроса читабельнее и быстрее.

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

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