Сложная оконная функция
Дается файл в формате csv.
client_id | timestamp |
---|---|
8225501 | 1722747654 |
8225501 | 1722747683 |
9609244 | 1722747693 |
... | ... |
Надо вывести за каждый день количество таких client_id
, которые встречались за последние 30 дней не менее 5 раз. Должны также учитываться client_id
, не присутствующие в данный день.
Вопрос: можно ли создать свою функцию для окна (фрейма), наподобие приведенной ниже?
SET @func = (SELECT SUM(COUNT(*)) OVER()
FROM w
GROUP BY id
HAVING COUNT(*) >= 5);
WITH a AS (
SELECT timestamp / 24 / 3600 AS day,
client_id AS id
FROM dataset)
SELECT DISTINCT(day),
@func OVER w AS cnt
FROM a
WINDOW w AS (ORDER BY day
RANGE BETWEEN 30 PRECEDING AND CURRENT ROW)
Ответы (2 шт):
Автор решения: pegoopik
→ Ссылка
Смутно описано ТЗ, но попробуйте так:
SELECT day, id
FROM(
SELECT day, id,
COUNT(*)OVER(PARTITION BY id ORDER BY day RANGE 30 PRECEDING AND CURRENT ROW)Cnt_Client
FROM(
SELECT
client_id AS id,
timestamp / 24 / 3600 AS day
FROM dataset
)T
)T
WHERE Cnt_Client >= 5
GROUP BY day, id
Автор решения: ValNik
→ Ссылка
Пример
- Сперва группируем по дням и клиентам - сколько раз клиент был за этот день
- Вычисляем с помощью оконной функции, сколько раз клиент был за последние 30 дней, считая от даты в текущей строке. Окно
range between interval 30 day preceding and current row
- Для каждой даты вычисляем число клиентов в этот день, у которых количество присутствия в предыдущие 30 дней >=5
Ваши данные для пример расширил для показа суммирования за день и 30 предыдущих дней.
select dt,sum(case when cntClientLast30day>=5 then 1 else 0 end) cntClientsGe5time30day
from(
select *
,sum(cntClientDay)over(partition by client_id order by dt
range between interval 30 day preceding and current row ) cntClientLast30day
from(
select client_id,cast(from_unixtime(timestamp) as date) dt
,count(*) cntClientDay
from test
group by client_id,cast(from_unixtime(timestamp) as date)
)a
)b
group by dt
dt | cntClientsGt5time30day |
---|---|
2024-08-04 | 2 |
2024-08-09 | 1 |
2024-08-10 | 1 |
2024-08-11 | 1 |
2024-08-12 | 1 |
2024-08-27 | 1 |
2024-09-08 | 1 |
2024-09-19 | 0 |
2024-10-01 | 0 |
select *
,sum(cntClientDay)over(partition by client_id order by dt
range between interval 1 month preceding and current row ) cntClientLast30day
from(
select client_id,cast(from_unixtime(timestamp) as date) dt
,count(*) cntClientDay
from test
group by client_id,cast(from_unixtime(timestamp) as date)
)a
order by dt,client_id
client_id | dt | cntClientDay | cntClientLast30day |
---|---|---|---|
8225501 | 2024-08-04 | 5 | 5 |
9609244 | 2024-08-04 | 6 | 6 |
8225501 | 2024-08-09 | 1 | 6 |
8225501 | 2024-08-10 | 1 | 7 |
8225501 | 2024-08-11 | 1 | 8 |
8225501 | 2024-08-12 | 1 | 9 |
8225501 | 2024-08-27 | 1 | 10 |
8225501 | 2024-09-08 | 1 | 6 |
9609244 | 2024-09-08 | 1 | 1 |
8225501 | 2024-09-19 | 1 | 3 |
8225501 | 2024-10-01 | 1 | 3 |
select client_id,cast(from_unixtime(timestamp) as date) dt
,count(*) cntClientDay
from test
group by client_id,cast(from_unixtime(timestamp) as date)
client_id | dt | cntClientDay |
---|---|---|
8225501 | 2024-08-04 | 5 |
9609244 | 2024-08-04 | 6 |
9609244 | 2024-09-08 | 1 |
8225501 | 2024-08-09 | 1 |
8225501 | 2024-08-10 | 1 |
8225501 | 2024-08-11 | 1 |
8225501 | 2024-08-12 | 1 |
8225501 | 2024-08-27 | 1 |
8225501 | 2024-09-08 | 1 |
8225501 | 2024-09-19 | 1 |
8225501 | 2024-10-01 | 1 |
Данные для примера
select * ,from_unixtime(timestamp) dttm
from test;
client_id | timestamp | dttm |
---|---|---|
8225501 | 1722747654 | 2024-08-04 05:00:54 |
8225501 | 1722747683 | 2024-08-04 05:01:23 |
9609244 | 1722747693 | 2024-08-04 05:01:33 |
9609244 | 1722757693 | 2024-08-04 07:48:13 |
9609244 | 1722767693 | 2024-08-04 10:34:53 |
9609244 | 1722777693 | 2024-08-04 13:21:33 |
9609244 | 1722787693 | 2024-08-04 16:08:13 |
9609244 | 1722797693 | 2024-08-04 18:54:53 |
9609244 | 1725797693 | 2024-09-08 12:14:53 |
8225501 | 1722757683 | 2024-08-04 07:48:03 |
8225501 | 1722767683 | 2024-08-04 10:34:43 |
8225501 | 1722777683 | 2024-08-04 13:21:23 |
8225501 | 1723177683 | 2024-08-09 04:28:03 |
8225501 | 1723277683 | 2024-08-10 08:14:43 |
8225501 | 1723377683 | 2024-08-11 12:01:23 |
8225501 | 1723477683 | 2024-08-12 15:48:03 |
8225501 | 1724777683 | 2024-08-27 16:54:43 |
8225501 | 1725777683 | 2024-09-08 06:41:23 |
8225501 | 1726777683 | 2024-09-19 20:28:03 |
8225501 | 1727777683 | 2024-10-01 10:14:43 |
Если же нужно вычислять окно (30 дней) от данной строки с учетом времени, п1. и п.2 нужно переставить.