Vraťte pouze minuty s aktivitou
Nejkratší
SELECT DISTINCT
date_trunc('minute', "when") AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY 1;
Použijte date_trunc() , vrátí přesně to, co potřebujete.
Nezahrnujte id v dotazu, protože chcete GROUP BY minutové řezy.
count() se obvykle používá jako jednoduchá agregační funkce. Připojení OVER klauzule z něj dělá funkci okna. Vynechat PARTITION BY v definici okna - chcete průběžný počet přes všechny řádky . Ve výchozím nastavení se to počítá od prvního řádku po posledního partnera aktuálního řádku, jak je definováno v ORDER BY . Manuál:
Výchozí možnost orámování je
RANGE UNBOUNDED PRECEDING, což je totéž jakoRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. PomocíORDER BY,toto nastaví rámec tak, aby byly všechny řádky od začátku oddílu až po posledníORDER BYaktuálního řádku peer.
A to je náhodou přesně co potřebujete.
Použijte count(*) spíše než count(id) . Lépe to odpovídá vaší otázce („počet řádků“). Obecně je o něco rychlejší než count(id) . A i když bychom mohli předpokládat, že id je NOT NULL , nebyl v otázce specifikován, takže count(id) je nesprávný , přísně vzato, protože hodnoty NULL se nepočítají s count(id) .
Nemůžete GROUP BY minutové řezy na stejné úrovni dotazu. Agregační funkce jsou použity před okenní funkce, funkce okna count(*) by tímto způsobem viděl pouze 1 řádek za minutu.
Můžete však SELECT DISTINCT , protože DISTINCT se použije po funkce okna.
ORDER BY 1 je jen zkratka pro ORDER BY date_trunc('minute', "when") zde.1 je poziční odkaz na 1. výraz v SELECT seznam.
Použijte to_char() pokud potřebujete formátovat výsledek. Jako:
SELECT DISTINCT
to_char(date_trunc('minute', "when"), 'DD.MM.YYYY HH24:MI') AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY date_trunc('minute', "when");
Nejrychlejší
SELECT minute, sum(minute_ct) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) sub
ORDER BY 1;
Podobně jako výše, ale:
K agregaci a počítání řádků za minutu používám poddotaz. Tímto způsobem získáme 1 řádek za minutu bez DISTINCT ve vnějším SELECT .
Použijte sum() jako funkci agregace oken nyní k sečtení počtů z dílčího dotazu.
Zjistil jsem, že je to podstatně rychlejší s mnoha řádky za minutu.
Zahrnout minuty bez aktivity
Nejkratší
@GabiMe se v komentáři zeptala, jak získat jeden řádek za každý minute v časovém rámci, včetně těch, kde nenastala žádná událost (žádný řádek v základní tabulce):
SELECT DISTINCT
minute, count(c.minute) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (SELECT date_trunc('minute', "when") FROM tbl) c(minute) USING (minute)
ORDER BY 1;
Vygenerujte řádek pro každou minutu v časovém rámci mezi první a poslední událostí pomocí generate_series() - zde přímo na základě agregovaných hodnot z dílčího dotazu.
LEFT JOIN ke všem časovým razítkům zkráceným na minutu a počítat. NULL hodnoty (kde neexistuje žádný řádek) se nepřidávají k průběžnému počtu.
Nejrychlejší
S CTE:
WITH cte AS (
SELECT date_trunc('minute', "when") AS minute, count(*) AS minute_ct
FROM tbl
GROUP BY 1
)
SELECT m.minute
, COALESCE(sum(cte.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(min(minute), max(minute), interval '1 min')
FROM cte
) m(minute)
LEFT JOIN cte USING (minute)
ORDER BY 1;
Opět v prvním kroku agregujte a počítejte řádky za minutu, odpadá nutnost pozdějšího DISTINCT .
Liší se od count() , sum() může vrátit NULL . Výchozí hodnota je 0 s COALESCE .
S mnoha řádky a indexem na "when" tato verze s poddotazem byla nejrychlejší mezi několika variantami, které jsem testoval s Postgres 9.1 - 9.4:
SELECT m.minute
, COALESCE(sum(c.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) c USING (minute)
ORDER BY 1;