PostgreSQL: uruchamianie liczby wierszy dla zapytania 'na minutę'
Muszę sprawdzić dla każdej minuty całkowitą liczbę wierszy do tej minuty.
Najlepsze, co do tej pory udało mi się osiągnąć, nie daje rady. Zwraca liczbę na minutę, a nie całkowitą liczbę do każdej minuty:
SELECT COUNT(id) AS count
, EXTRACT(hour from "when") AS hour
, EXTRACT(minute from "when") AS minute
FROM mytable
GROUP BY hour, minute
1 answers
Zwraca tylko minuty z aktywnością
Najkrótsza
SELECT DISTINCT
date_trunc('minute', "when") AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY 1;
Użycie
date_trunc()
, zwraca dokładnie to, czego potrzebujesz.Nie włączaj
id
do zapytania, ponieważ chceszGROUP BY
minute plasterki.-
count()
jest zwykle używany jako zwykła funkcja agregująca . Dodanie klauzuliOVER
czyni ją funkcją okna . PomińPARTITION BY
w definicji okna - chcesz, aby liczył wszystkie wiersze. Domyślnie liczy się od pierwszego wiersza do ostatniego równika bieżącego wiersza zgodnie z definicjąORDER BY
. cytuję instrukcję :Domyślną opcją kadrowania jest
RANGE UNBOUNDED PRECEDING
, czyli tak samo jakRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. ZORDER BY
, to ustawia ramkę jako wszystkie wiersze od uruchomienia partycji przez ostatniORDER BY
peer bieżącego wiersza.I to jest dokładnie to, czego potrzebujesz.
Użyj
count(*)
zamiastcount(id)
. Lepiej pasuje twoje pytanie ("liczba wierszy"). Na ogół jest nieco szybszy niżcount(id)
. I chociaż możemy założyć, żeid
jestNOT NULL
, nie zostało to określone w pytaniu, więccount(id)
jest błędne , ściśle mówiąc, ponieważ wartości NULL nie są liczone zcount(id)
.Nie możesz
GROUP BY
minut na tym samym poziomie zapytania. Funkcje zbiorcze są stosowane przed funkcje okna, funkcja oknacount(*)
będzie widzieć tylko 1 wiersz na minutę to sposób.
Można jednakSELECT DISTINCT
, ponieważ {[27] } jest stosowane po funkcje okna.ORDER BY 1
to tylko skrót odORDER BY date_trunc('minute', "when")
tutaj.1
jest odniesieniem pozycyjnym do pierwszego wyrażenia z listySELECT
.-
Użycie
to_char()
jeśli chcesz sformatować wynik. Lubię:
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");
Najszybszy
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;
Podobnie jak wyżej, ale:
Używam subquery do agreguj i licz wiersze na minutę. W ten sposób otrzymujemy 1 wiersz na minutę bez
DISTINCT
w zewnętrznymSELECT
.Użyj
sum()
jako funkcji agregującej okno, aby dodać liczniki z zapytania podrzędnego.
Okazało się, że jest to znacznie szybsze z wieloma rzędami na minutę.
Dołącz minuty bez aktywności
Najkrótsza
@GabiMe zapytała w komentarzu jak zdobyć eOne row dla co minute
W ramach czasowych, łącznie z tymi, w których nie wystąpiło zdarzenie (brak wiersza w tabeli bazowej):
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;
Generuje wiersz dla każdej minuty w przedziale czasowym między pierwszym i ostatnim wydarzeniem z
generate_series()
- tutaj bezpośrednio na podstawie zagregowanych wartości z zapytania podrzędnego.LEFT JOIN
do wszystkich znaczników czasu obciętych do minuty i liczą.NULL
wartości (gdzie nie ma wiersza) nie dodają się do bieżącej liczby.
Najszybszy
Z 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;
Ponownie, agreguj i licz wiersze na minutę w pierwszym kroku, pomija potrzebę późniejszego
DISTINCT
.Różni się od
count()
,sum()
can returnNULL
. Domyślnie0
ZCOALESCE
.
Z wieloma wierszami i indeksem na "when"
Ta wersja z subquery była najszybsza wśród kilku wariantów, które testowałem z 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;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-26 00:03:40