а ось складніша SQL задачка
Oct. 22nd, 2025 05:47 pmСпряжена до попередньої задачi.
Дано: таблиця з повідомленнями, які юзери шлють комусь там. Нас хвилюють три колонки: юзер айді uid, номер контакта num, час t (ну і ще всякі, неважливо)
Написати такий запит в цю таблицю (SELECT *...) щоби порахувало, скільком різним номерам підряд пішло повідомлення від нашого юзера
Тобто, уявіть собі, що ви дивитися на повідомлення лише від одного юзера, уже відсортовані за часом. Повідомлення ідуть на такі номери:
10, 11, 12, 10, 13, 14, 15, 11, 16, 17, 16
Потрібні мені цифри будуть такі:
3, 6, 8, 8, 8, 8, 8, 8, 8, 8, 2
Фактично, задача: для кожного елементу впорядкованої послідовності порахувати ширину максимального вікна, в яке входить цей елемент, і в якому всі елементи різні.
Я поки що не знаю. В якійсь стандартній мові програмування -- хай неелеґантно і складно в плані computational complexity, але таке написати я зможу, а в сіквелі якось завис.
Дано: таблиця з повідомленнями, які юзери шлють комусь там. Нас хвилюють три колонки: юзер айді uid, номер контакта num, час t (ну і ще всякі, неважливо)
Написати такий запит в цю таблицю (SELECT *...) щоби порахувало, скільком різним номерам підряд пішло повідомлення від нашого юзера
Тобто, уявіть собі, що ви дивитися на повідомлення лише від одного юзера, уже відсортовані за часом. Повідомлення ідуть на такі номери:
10, 11, 12, 10, 13, 14, 15, 11, 16, 17, 16
Потрібні мені цифри будуть такі:
3, 6, 8, 8, 8, 8, 8, 8, 8, 8, 2
Фактично, задача: для кожного елементу впорядкованої послідовності порахувати ширину максимального вікна, в яке входить цей елемент, і в якому всі елементи різні.
Я поки що не знаю. В якійсь стандартній мові програмування -- хай неелеґантно і складно в плані computational complexity, але таке написати я зможу, а в сіквелі якось завис.
no subject
Date: 2025-10-23 05:21 am (UTC)(0, 10, nextIndexOf10), (1, 11, nextIndexOf11), (2, 12, nextIndexOf12)
Але цей напрямок може бути тупіковий, особливо якщо SQL взагалі без циклів.
no subject
Date: 2025-10-23 06:25 am (UTC)no subject
Date: 2025-10-23 08:04 am (UTC)Питання: це абстрактна задача, чи прикладна?
no subject
Date: 2025-10-23 08:08 am (UTC)no subject
Date: 2025-10-23 09:03 am (UTC)no subject
Date: 2025-10-23 06:12 pm (UTC)Можна, звичайно, вікно за кількістю рядків, воно, звичайно, теж варіант.
no subject
Date: 2025-10-23 09:43 am (UTC)no subject
Date: 2025-10-23 06:14 pm (UTC)Плюс, у нас важливий челендж -- не лише ловити, а мати конкретну метрику, яка виправдовує це діло: "чувак, ти послав 42 повідомлення різним людям, може, ти спамер?" -- воно закриває деякі бізнесові і юридичні потреби.
no subject
Date: 2025-10-23 06:26 pm (UTC)no subject
Date: 2025-10-23 01:19 pm (UTC)UPD: without join
UPD 2: not quite there but hopefully in the right direction.
WITH numbered AS ( SELECT sender, receiver, _time, ROW_NUMBER() OVER (PARTITION BY sender ORDER BY _time) AS pos FROM tbl ), next_duplicate AS ( SELECT *, LEAD(pos) OVER (PARTITION BY sender, receiver ORDER BY pos) AS next_same_receiver FROM numbered ) SELECT sender, receiver, _time, COALESCE( MIN(next_same_receiver) OVER ( PARTITION BY sender ORDER BY pos ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ), MAX(pos) OVER (PARTITION BY sender) + 1 ) - pos AS range_width FROM next_duplicateno subject
Date: 2025-10-23 03:30 pm (UTC)Але якось надто складно виходить, навіть коли вийде
no subject
Date: 2025-10-23 03:46 pm (UTC)If we want "at the current record or before it" semantics instead then add one more column to the middle step.
Where it calls LEAD() for the next dupe it should also call LAG() for the previous dupe. Then adjust range_width calculation accordingly.
no subject
Date: 2025-10-23 02:02 pm (UTC)I suspect the example is not quite right: 6 implies "starts at the current record" and the last 2 implies "starts before".
no subject
Date: 2025-10-23 03:17 pm (UTC)no subject
Date: 2025-10-23 03:24 pm (UTC)If we want "at the current or before" semantics then the required change is relatively easy. Where it calls LEAD() (for the next dupe) it should also call LAG() for the previous dupe.
no subject
Date: 2025-10-23 04:13 pm (UTC)WITH numbered AS ( SELECT sender, receiver, _time, ROW_NUMBER() OVER ( PARTITION BY sender ORDER BY _time ) AS pos FROM tbl ), duplicates AS ( SELECT *, LAG(pos) OVER ( PARTITION BY sender, receiver ORDER BY pos ) AS prev_same_receiver, LEAD(pos) OVER ( PARTITION BY sender, receiver ORDER BY pos ) AS next_same_receiver FROM numbered ) SELECT sender, receiver, _time, COALESCE( MIN(next_same_receiver) OVER ( PARTITION BY sender ORDER BY pos ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ), MAX(pos) OVER (PARTITION BY sender) + 1 ) - COALESCE( MAX(prev_same_receiver) OVER ( PARTITION BY sender ORDER BY pos ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) + 1, pos ) AS range_width FROM duplicatesno subject
Date: 2025-10-23 04:52 pm (UTC)no subject
Date: 2025-10-23 07:40 pm (UTC)no subject
Date: 2025-10-23 08:02 pm (UTC)no subject
Date: 2025-10-23 08:55 pm (UTC)no subject
Date: 2025-10-23 09:10 pm (UTC)Як казав один дідо, "The most noble fate a man can endure is to place his own mortal body between his loved home and the war's desolation".
Hier stehe ich. Ich kann nicht anders.