TGViewer
SQL и Анализ данных SQL и Анализ данных @databases_tg · 12.5K subscribers
Post #1119 3.47K
Microsoft SQL Interview Question — разбор №2: Early Responders

Задача: найти топ-3 пользователей, которые чаще всего отвечали на сообщения в течение 5 минут в августе 2022.
Нужно вывести их sender_id и число «быстрых ответов».

Данные: таблица messages(message_id, sender_id, receiver_id, content, sent_date).

Подход:
— Фильтруем август полуинтервалом [2022-08-01, 2022-09-01).
— Группируем переписку по паре пользователей (conv_id = min(sender,receiver)–max(sender,receiver)).
— Используем LAG по conv_id, чтобы взять предыдущее сообщение в диалоге.
— Быстрый ответ — когда направление сменилось и прошло ≤ 5 минут.

Решение (T-SQL):

WITH aug AS (
SELECT message_id, sender_id, receiver_id, sent_date
FROM messages
WHERE sent_date >= '2022-08-01'
AND sent_date < '2022-09-01'
),
conv AS (
SELECT *,
CONCAT(
IIF(sender_id < receiver_id, sender_id, receiver_id), '-',
IIF(sender_id < receiver_id, receiver_id, sender_id)
) AS conv_id
FROM aug
),
seq AS (
SELECT *,
LAG(sender_id) OVER (PARTITION BY conv_id ORDER BY sent_date, message_id) AS prev_sender,
LAG(sent_date) OVER (PARTITION BY conv_id ORDER BY sent_date, message_id) AS prev_time
FROM conv
),
fast AS (
SELECT sender_id
FROM seq
WHERE prev_sender IS NOT NULL
AND sender_id <> prev_sender
AND DATEDIFF(minute, prev_time, sent_date) <= 5
)
SELECT TOP (3)
sender_id,
COUNT(*) AS fast_reply_count
FROM fast
GROUP BY sender_id
ORDER BY COUNT(*) DESC, sender_id;


Вариант с учётом ничьих (возьмёт всех на 1-3 местах):

WITH aug AS (
SELECT message_id, sender_id, receiver_id, sent_date
FROM messages
WHERE sent_date >= '2022-08-01'
AND sent_date < '2022-09-01'
),
conv AS (
SELECT *,
CONCAT(
IIF(sender_id < receiver_id, sender_id, receiver_id), '-',
IIF(sender_id < receiver_id, receiver_id, sender_id)
) AS conv_id
FROM aug
),
seq AS (
SELECT *,
LAG(sender_id) OVER (PARTITION BY conv_id ORDER BY sent_date, message_id) AS prev_sender,
LAG(sent_date) OVER (PARTITION BY conv_id ORDER BY sent_date, message_id) AS prev_time
FROM conv
),
fast AS (
SELECT sender_id
FROM seq
WHERE prev_sender IS NOT NULL
AND sender_id <> prev_sender
AND DATEDIFF(minute, prev_time, sent_date) <= 5
),
agg AS (
SELECT sender_id, COUNT(*) AS fast_reply_count
FROM fast
GROUP BY sender_id
),
ranked AS (
SELECT sender_id, fast_reply_count,
DENSE_RANK() OVER (ORDER BY fast_reply_count DESC) AS rnk
FROM agg
)
SELECT sender_id, fast_reply_count
FROM ranked
WHERE rnk <= 3
ORDER BY fast_reply_count DESC, sender_id;


Почему так:
— Диапазон дат без функций сохраняет использование индекса по sent_date.
— LAG по conv_id гарантирует, что сравниваем соседние сообщения в одном диалоге.
— Проверяем смену направления (sender_id ≠ prev_sender) и порог по времени (≤ 5 минут).
  • 👍 8
  • ❤ 3
  • 😁 2
  • 🥰 1
  • 🤨 1
  • 😭 1
More from @databases_tg
  1. Oct 2, 2026Как SQLite превращает числа в текст в 2 раза быстрее? Трюк с парами цифр Обычно число пере…
  2. Oct 2, 2026В субботу, 17 октября, Москва станет точкой притяжения для всех специалистов в области Rec…
  3. Oct 1, 2026Жиз
  4. Sep 30, 2026📝 5 уровней ИИ-агентов: от промпта до продакшена Context, loop, Jev, harness и evals: раз…
  5. Sep 26, 2026UPDATE — оператор обновления данных в MySQL 🗂️ Если в таблице нужно изменить значение в у…
  6. Sep 25, 2026🧠 SQL-задача с подвохом Есть таблица транзакций: CREATE TABLE transactions ( id int PRIMA…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →