Собесов

Учи.ру: ученики с долей заданий в режиме «Урок» более 50%

SQLУсловные агрегацииСредняяMiddle

Условие

В Учи.ру дети решают задания, доступ платный. Учитель может включить функцию «Урок», и в течение часа все задания становятся бесплатными.

Посчитать количество учеников, у которых доля заданий, решённых во время функции «Урок», составляет более 50% от общего числа решённых ими заданий.

Таблицы:

  • sessions(card_id, session_time, user_id, teacher_id) — решённые задания.
  • lessons(teacher_id, lesson_start, lesson_end) — окна включённой функции.

Решение

Подход

  1. Для каждого решённого задания узнать: было ли это в окне lesson_start..lesson_end по тому же teacher_id.
  2. На уровне ученика посчитать долю: n_lesson / n_total.
  3. Отфильтровать долю > 50%.
  4. Подсчитать число учеников.

SQL

WITH flagged AS (
  SELECT
    s.user_id,
    s.card_id,
    CASE WHEN EXISTS (
      SELECT 1 FROM lessons l
      WHERE l.teacher_id = s.teacher_id
        AND s.session_time >= l.lesson_start
        AND s.session_time <  l.lesson_end
    ) THEN 1 ELSE 0 END AS in_lesson
  FROM sessions s
),
agg AS (
  SELECT
    user_id,
    SUM(in_lesson)        AS in_lesson_cnt,
    COUNT(*)              AS total_cnt,
    1.0 * SUM(in_lesson) / COUNT(*) AS share
  FROM flagged
  GROUP BY user_id
)
SELECT COUNT(*) AS n_users
FROM agg
WHERE share > 0.5;

Альтернатива через JOIN

WITH flagged AS (
  SELECT
    s.user_id, s.card_id,
    MAX(CASE WHEN l.teacher_id IS NOT NULL THEN 1 ELSE 0 END) AS in_lesson
  FROM sessions s
  LEFT JOIN lessons l
    ON l.teacher_id = s.teacher_id
   AND s.session_time >= l.lesson_start
   AND s.session_time <  l.lesson_end
  GROUP BY s.user_id, s.card_id
)
...

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

  1. У ученика может быть несколько учителей в разное время — учитывать teacher_id сессии, а не «последнего учителя».
  2. Если окно lesson_end < lesson_start (бракованные данные) — WHERE l.lesson_end > l.lesson_start для безопасности.
  3. Совмещение: EXISTS быстрее, чем LEFT JOIN ... GROUP BY с дублями (если у учителя несколько lessons, одно задание попадёт в несколько строк).
  4. > 50% строго или >= 50%? Уточнять.
  5. На больших данных индекс по (teacher_id, lesson_start) критичен.

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

Помечаем in_lesson через EXISTS по teacher_id и временному диапазону, считаем долю на ученика, фильтруем > 0.5, считаем количество.

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

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

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