PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL:liczenie wierszy dla zapytania "po minucie"

Zwróć tylko minuty z aktywnością

Najkrótszy

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żyj date_trunc() , zwraca dokładnie to, czego potrzebujesz.

Nie dołączaj id w zapytaniu, ponieważ chcesz GROUP BY minutowe plasterki.

count() jest zwykle używany jako zwykła funkcja agregująca. Dołączanie OVER klauzula sprawia, że ​​jest to funkcja okna. Pomiń PARTITION BY w definicji okna - chcesz mieć bieżącą liczbę na wszystkich wierszach . Domyślnie liczy się to od pierwszego wiersza do ostatniego elementu równorzędnego w bieżącym wierszu, zgodnie z definicją ORDER BY . Instrukcja:

Domyślną opcją kadrowania jest RANGE UNBOUNDED PRECEDING , który jest taki sam jak RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . Z ORDER BY , ustawia to ramkę na wszystkie wiersze od partycji, począwszy od ostatniego ORDER BY bieżącego wiersza równorzędny.

I tak się składa dokładnie czego potrzebujesz.

Użyj count(*) zamiast count(id) . Lepiej pasuje do Twojego pytania („liczba wierszy”). Zwykle jest nieco szybszy niż count(id) . I chociaż możemy założyć, że id jest NOT NULL , nie zostało to określone w pytaniu, więc count(id) jest nieprawidłowa , ściśle mówiąc, ponieważ wartości NULL nie są liczone za pomocą count(id) .

Nie możesz GROUP BY wycinki minutowe na tym samym poziomie zapytania. Funkcje agregujące są stosowane przed funkcje okna, funkcja okna count(*) widziałby w ten sposób tylko 1 wiersz na minutę.
Możesz jednak SELECT DISTINCT , ponieważ DISTINCT jest stosowany po funkcje okna.

ORDER BY 1 to po prostu skrót dla ORDER BY date_trunc('minute', "when") tutaj.
1 jest referencją pozycyjną do pierwszego wyrażenia w SELECT lista.

Użyj to_char() jeśli potrzebujesz sformatować wynik. Na przykład:

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 powyżej, ale:

Używam podzapytania do agregowania i liczenia wierszy na minutę. W ten sposób otrzymujemy 1 wiersz na minutę bez DISTINCT w zewnętrznym SELECT .

Użyj sum() jako funkcja agregująca okna, aby dodać liczniki z podzapytania.

Odkryłem, że jest to znacznie szybsze przy wielu rzędach na minutę.

Uwzględnij minuty bez aktywności

Najkrótszy

@GabiMe zapytał w komentarzu, jak uzyskać jeden wiersz dla każdego minute w ramach czasowych, w tym tych, w których nie wystąpiło żadne 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;

Generuj wiersz dla każdej minuty w przedziale czasowym między pierwszym a ostatnim zdarzeniem za pomocą generate_series() - tutaj bezpośrednio na podstawie zagregowanych wartości z podzapytania.

LEFT JOIN do wszystkich znaczników czasu obciętych do minuty i liczenia. NULL wartości (gdzie nie istnieje żaden wiersz) nie są dodawane 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 to potrzebę późniejszego DISTINCT .

Różni się od count() , sum() może zwrócić NULL . Domyślnie 0 z COALESCE .

Z wieloma wierszami i indeksem "when" ta wersja z podzapytaniem była najszybsza spośród kilku wariantów, które testowałem z Postgresem 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;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Instalacja PostgreSQL 9 w systemie Windows:Nie można pisać w ścieżce środowiska TEMP.

  2. Nie można połączyć się z lokalnym PostgreSQL

  3. Powolne porządkowanie zapytań według kolumny w połączonej tabeli

  4. Najszybsze sprawdzenie, czy wiersz istnieje w PostgreSQL

  5. Jak cicho zainstalować Postgresql w Ubuntu przez. Plik Dockera?