Собесов

SQL: город с максимальной нагрузкой по завершённым обучениям

SQLGROUP BY + ORDER BY с тай-брейкеромСредняяJunior

Условие

Те же три таблицы (students, enrollments, reviews).

Напишите запрос, который определит город с наибольшей суммарной «нагрузкой» по завершённым обучениям. Если таких городов несколько — выберите тот, чьё название идёт раньше по алфавиту.

«Нагрузка» = сумма progress_pct по завершённым (status = 'completed') обучениям студентов из этого города.

PostgreSQL 15.5.

Решение

Подход

  1. Соединить students с enrollments по student_id.
  2. Отфильтровать status = 'completed'.
  3. Сгруппировать по городу, посчитать сумму progress_pct.
  4. Отсортировать: сначала по нагрузке (DESC), при равенстве — по названию (ASC).
  5. Взять первую строку.

Реализация

SELECT s.city
FROM students s
JOIN enrollments e ON e.student_id = s.student_id
WHERE e.status = 'completed'
GROUP BY s.city
ORDER BY SUM(e.progress_pct) DESC, s.city ASC
LIMIT 1;

Сложность

Один проход по enrollments + хеш-агрегация по city. На больших таблицах помогает индекс по enrollments(status, student_id) и students(student_id).

Альтернатива — окно для тай-брейкера

WITH agg AS (
    SELECT s.city, SUM(e.progress_pct) AS load
    FROM students s
    JOIN enrollments e ON e.student_id = s.student_id
    WHERE e.status = 'completed'
    GROUP BY s.city
),
ranked AS (
    SELECT city, load, RANK() OVER (ORDER BY load DESC) AS rk
    FROM agg
)
SELECT city FROM ranked
WHERE rk = 1
ORDER BY city ASC
LIMIT 1;

Длиннее, но при необходимости вернуть «всех лидеров» — пригодится.

Подводные камни

  1. ORDER BY SUM(progress_pct) DESC без второго ключа. При равной нагрузке порядок не определён — разные запуски могут дать разный город. Условие явно требует тай-брейкер.
  2. LEFT JOIN вместо INNER. Если использовать LEFT JOIN students → enrollments, получите города без обучений с NULL-нагрузкой. SUM(NULL) = NULL, такие строки попадут в результат с NULL в нагрузке.
  3. Считать «нагрузку» как COUNT(*). Условие — SUM(progress_pct). Если 1 студент завершил 1 курс на 100% — нагрузка 100, а не 1.
  4. progress_pct для completed должен быть 100. Но в реальных данных может быть 99 или NULL. Доверяйте полю status — его явно требует условие.

Эталонный ответ

SELECT s.city
FROM students s
JOIN enrollments e ON e.student_id = s.student_id
WHERE e.status = 'completed'
GROUP BY s.city
ORDER BY SUM(e.progress_pct) DESC, s.city ASC
LIMIT 1;

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти