sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur man lägger till en löpande räkning till rader i en "serie" av på varandra följande dagar

Bygger vidare på denna tabell (använder inte SQL-sökordet "datum" som kolumnnamn.):

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

Fråga:

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;

Subtrahera ett date från ett annat date ger ett integer . Eftersom du letar efter dagar i följd blir varje nästa rad större med en . Om vi ​​subtraherar row_number() från det hamnar hela raden i samma grupp (grp ) per pid . Då är det enkelt att dela ut antal per grupp.

grp beräknas med två subtraktioner, som bör vara snabbast. Ett lika snabbt alternativ kan vara:

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

En multiplikation, en subtraktion. Strängsammansättning och gjutning är dyrare. Testa med EXPLAIN ANALYZE .

Glöm inte att partitionera med pid dessutom i båda steg, eller så blandar du oavsiktligt grupper som borde separeras.

Använder en underfråga, eftersom det vanligtvis är snabbare än en CTE . Det finns inget här som en vanlig underfråga inte kunde göra.

Och eftersom du nämnde det:dense_rank() är uppenbarligen inte nödvändigt här. Grundläggande row_number() gör jobbet.



  1. Returmeddelande med felkod i Oracle Stored Proc

  2. MySQL Välj rader vid första förekomsten av varje unikt värde

  3. 2 sätt att skapa en tabell om den inte finns i SQL Server

  4. SQL-fråga för att extrahera alla WordPress-inlägg med kategorier