PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL:текущ брой редове за заявка „по минута“

Връщане само на минути с активност

Най-кратък

SELECT DISTINCT
       date_trunc('minute', "when") AS minute
     , count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM   mytable
ORDER  BY 1;

Използвайте date_trunc() , връща точно това, от което се нуждаете.

Не включвайте id в заявката, тъй като искате да GROUP BY минути филийки.

count() обикновено се използва като обикновена агрегатна функция. Добавяне на OVER клауза го прави функция прозорец. Пропуснете PARTITION BY в дефиницията на прозореца - искате текущ брой за всички редове . По подразбиране това се брои от първия ред до последния партньор на текущия ред, както е дефинирано от ORDER BY . Ръководството:

Опцията за рамкиране по подразбиране е RANGE UNBOUNDED PRECEDING , което е същото като RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . С ORDER BY , това задава рамката да бъде всички редове от началото на дяла до последния ORDER BY на текущия ред връстник.

И това се случва точно това, от което се нуждаете.

Използвайте count(*) вместо count(id) . По-добре отговаря на вашия въпрос („брой редове“). Обикновено е малко по-бързо отколкото count(id) . И макар че можем да приемем, че id е NOT NULL , не е посочено във въпроса, така че count(id) е грешно , строго погледнато, защото NULL стойностите не се отчитат с count(id) .

Не можете да GROUP BY минути срезове на същото ниво на заявка. Агрегатните функции се прилагат преди функции на прозореца, функцията на прозореца count(*) ще вижда само 1 ред в минута по този начин.
Можете обаче да SELECT DISTINCT , защото DISTINCT се прилага след функции на прозореца.

ORDER BY 1 е просто стенография за ORDER BY date_trunc('minute', "when") тук.
1 е позиционна препратка към 1-вия израз в SELECT списък.

Използвайте to_char() ако трябва да форматирате резултата. Като:

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");

Най-бърз

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;

Много като горното, но:

Използвам подзаявка за агрегиране и преброяване на редове в минута. По този начин получаваме 1 ред в минута без DISTINCT във външния SELECT .

Използвайте sum() като агрегатна функция на прозореца сега, за да добавите броя от подзаявката.

Открих, че това е значително по-бързо с много редове в минута.

Включете минути без активност

Най-кратък

@GabiMe попита в коментар как да получите един ред за всички minute във времевата рамка, включително тези, при които не е настъпило събитие (няма ред в основната таблица):

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;

Генерирайте ред за всяка минута във времевата рамка между първото и последното събитие с generate_series() - тук директно въз основа на обобщени стойности от подзаявката.

LEFT JOIN до всички времеви марки, съкратени до минутите и отчитане. NULL стойности (където не съществува ред) не се добавят към текущия брой.

Най-бърз

С 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;

Отново, обобщавайте и броете редове в минута в първата стъпка, то пропуска необходимостта от по-късно DISTINCT .

Различно от count() , sum() може да върне NULL . По подразбиране е 0 с COALESCE .

С много редове и индекс на "when" тази версия с подзаявка беше най-бърза сред няколко варианта, които тествах с 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;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Django моделира един външен ключ към много таблици

  2. Как да отмените завъртане на таблица в PostgreSQL

  3. Как да потърся нулеви стойности в json поле тип postgresql?

  4. Как да съхранявате масив или множество стойности в една колона

  5. Преброяване на знаци в последователности чрез SQL