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 BY
aktuá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;