sql >> Database >  >> RDS >> PostgreSQL

Een lopende telling toevoegen aan rijen in een 'reeks' van opeenvolgende dagen

Voortbouwend op deze tabel (zonder het SQL-trefwoord "date" als kolomnaam.):

CREATE TABLE tbl(
  pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);

Vraag:

SELECT pid, the_date
     , row_number() OVER (PARTITION BY pid, grp ORDER BY the_date) AS in_streak
FROM  (
   SELECT *
        , the_date - '2000-01-01'::date
        - row_number() OVER (PARTITION BY pid ORDER BY the_date) AS grp
   FROM   tbl
) sub
ORDER  BY pid, the_date;

Een date aftrekken van een andere date levert een integer op . Aangezien u naar opeenvolgende dagen zoekt, zou elke volgende rij één groter zijn . Als we row_number() . aftrekken van daaruit komt de hele streak in dezelfde groep terecht (grp ) per pid . Dan is het eenvoudig om aantal per groep uit te delen.

grp wordt berekend met twee aftrekkingen, wat het snelst zou moeten zijn. Een even snel alternatief zou kunnen zijn:

the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp

Eén vermenigvuldiging, één aftrekking. String aaneenschakeling en gieten is duurder. Test met EXPLAIN ANALYZE .

Vergeet niet te partitioneren op pid bovendien in beide stappen, anders meng je per ongeluk groepen die gescheiden moeten worden.

Een subquery gebruiken, aangezien dat doorgaans sneller is dan een CTE . Er is hier niets dat een gewone subquery niet zou kunnen doen.

En aangezien je het noemde:dense_rank() is duidelijk niet hier nodig. Basis row_number() doet het werk.



  1. 5 manieren om hoofdletterongevoelig zoeken in SQLite te implementeren met volledige Unicode-ondersteuning

  2. SUM(subquery) in MYSQL

  3. Installeer en maak verbinding met PostgreSQL 10 op Ubuntu 16.04

  4. Gebruik MSSQL en MySQL met CodeIgniter