Условие
Те же три таблицы (students, enrollments, reviews).
Напишите запрос, который определит город с наибольшей суммарной «нагрузкой» по завершённым обучениям. Если таких городов несколько — выберите тот, чьё название идёт раньше по алфавиту.
«Нагрузка» = сумма progress_pct по завершённым (status = 'completed') обучениям студентов из этого города.
PostgreSQL 15.5.
Решение
Подход
- Соединить
studentsсenrollmentsпоstudent_id. - Отфильтровать
status = 'completed'. - Сгруппировать по городу, посчитать сумму
progress_pct. - Отсортировать: сначала по нагрузке (DESC), при равенстве — по названию (ASC).
- Взять первую строку.
Реализация
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;Длиннее, но при необходимости вернуть «всех лидеров» — пригодится.
Подводные камни
ORDER BY SUM(progress_pct) DESCбез второго ключа. При равной нагрузке порядок не определён — разные запуски могут дать разный город. Условие явно требует тай-брейкер.LEFT JOINвместоINNER. Если использоватьLEFT JOIN students → enrollments, получите города без обучений сNULL-нагрузкой.SUM(NULL) = NULL, такие строки попадут в результат сNULLв нагрузке.- Считать «нагрузку» как
COUNT(*). Условие —SUM(progress_pct). Если 1 студент завершил 1 курс на 100% — нагрузка100, а не1. 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;