Тестов случай:
CREATE TABLE tbl (date date, email text);
INSERT INTO tbl VALUES
('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-03', '[email protected]')
, ('2012-01-04', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]`')
;
Заявка - връща само дни, в които съществува запис в tbl
:
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN t.date - 2 AND t.date -- period of 3 days
) AS dist_emails
FROM tbl t
WHERE date BETWEEN '2012-01-01' AND '2012-01-06'
GROUP BY 1
ORDER BY 1;
Или - върнете всички дни в посочения диапазон, дори ако няма редове за деня:
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN g.date - 2 AND g.date
) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date);
db<>цигулка тук
Резултат:
day | dist_emails
-----------+------------
2012-01-01 | 3
2012-01-02 | 3
2012-01-03 | 3
2012-01-04 | 3
2012-01-05 | 1
2012-01-06 | 2
Това звучеше като работа за функции на прозореца в началото, но не намерих начин да дефинирам подходящата рамка на прозореца. Също така, според документация:
Функциите на прозореца за обобщени, за разлика от нормалните агрегатни функции, не позволяват
DISTINCT
илиORDER BY
да се използва в списъка с аргументи на функцията.
Затова го реших с корелирани подзаявки вместо това. Предполагам, че това е най-умният начин.
Между другото, "между посочената дата и преди 3 дни" ще бъде период от 4 дни. Определението ти е противоречиво.
Малко по-кратко, но по-бавно за няколко дни:
SELECT g.date, count(DISTINCT email) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date)
LEFT JOIN tbl t ON t.date BETWEEN g.date - 2 AND g.date
GROUP BY 1
ORDER BY 1;
Свързано:
- Генериране на времеви серии между две дати в PostgreSQL
- Подвижен брой редове във времевия интервал