Testgeval:
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]`')
;
Query - retourneert alleen dagen waarop een item bestaat in 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;
Of - retourneer alle dagen binnen het opgegeven bereik, zelfs als er geen rijen zijn voor de dag:
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<>viool hier
Resultaat:
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
Dit klonk als een baan voor raamfuncties in het begin, maar ik vond geen manier om het geschikte raamkozijn te definiëren. Ook, per documentatie:
Geaggregeerde vensterfuncties, in tegenstelling tot normale aggregatiefuncties, staan DISTINCT
niet toe of ORDER BY
te gebruiken in de lijst met functieargumenten.
Dus heb ik het in plaats daarvan opgelost met gecorreleerde subquery's. Ik denk dat dat de slimste manier is.
Trouwens, "tussen genoemde datum en 3 dagen geleden" zou een periode zijn van 4 dagen. Je definitie is daar tegenstrijdig.
Iets korter, maar een paar dagen langzamer:
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;
Gerelateerd:
- Tijdreeksen genereren tussen twee datums in PostgreSQL
- Rollend aantal rijen binnen tijdsinterval