Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Policz liczbę kolejnych wizyt

Brakowało mi tagu mysql i napisałem to rozwiązanie. Niestety, to nie działa w MySQL, ponieważ nie obsługuje funkcji okien .

I tak to publikuję, ponieważ włożyłem w to trochę wysiłku. Przetestowane z PostgreSQL. Działałby podobnie z Oracle lub SQL Server (lub jakimkolwiek innym przyzwoitym RDBMS, który obsługuje funkcje okien).

Konfiguracja testowa

CREATE TEMP TABLE v(id int, visit date);
INSERT INTO v VALUES
 (444631, '2011-11-07')
,(444631, '2011-11-06')
,(444631, '2011-11-05')
,(444631, '2011-11-04')
,(444631, '2011-11-02')
,(444631, '2011-11-01')
,(444632, '2011-12-02')
,(444632, '2011-12-03')
,(444632, '2011-12-05');

Prosta wersja

-- add 1 to "difference" to get number of days of the longest period
SELECT id, max(dur) + 1 as max_consecutive_days
FROM (

   -- calculate date difference of min and max in the group
   SELECT id, grp, max(visit) - min(visit) as dur
   FROM (

      -- consecutive days end up in a group
      SELECT *, sum(step) OVER (ORDER BY id, rn) AS grp
      FROM   (

         -- step up at the start of a new group of days
         SELECT id
               ,row_number() OVER w AS rn
               ,visit
               ,CASE WHEN COALESCE(visit - lag(visit) OVER w, 1) = 1
                THEN 0 ELSE 1 END AS step
         FROM   v
         WINDOW w AS (PARTITION BY id ORDER BY visit)
         ORDER  BY 1,2
         ) x
      ) y
      GROUP BY 1,2
   ) z
GROUP  BY 1
ORDER  BY 1
LIMIT  1;

Wyjście:

   id   | max_consecutive_days
--------+----------------------
 444631 |                    4

Szybciej / krócej

Później znalazłem jeszcze lepszy sposób. grp liczby nie są ciągłe (ale stale rosną). Nie ma znaczenia, ponieważ to tylko środek do celu:

SELECT id, max(dur) + 1 AS max_consecutive_days
FROM (
    SELECT id, grp, max(visit) - min(visit) AS dur
    FROM (
      -- subtract an integer representing the number of day from the row_number()
      -- creates a "group number" (grp) for consecutive days
      SELECT id
            ,EXTRACT(epoch from visit)::int / 86400
           - row_number() OVER (PARTITION BY id ORDER BY visit) AS grp
            ,visit
      FROM   v
      ORDER  BY 1,2
      ) x
    GROUP BY 1,2
    ) y
GROUP  BY 1
ORDER  BY 1
LIMIT  1;

Skrzypce SQL dla obu.

Więcej



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kolumna aktualizacji MySQL tylko wtedy, gdy wartość nie jest pusta, gdzie

  2. Kolumna alternatywnej tabeli MySQL

  3. Dodaj kolumnę MySQL, jeśli nie istnieje

  4. Czy mogę wykonać mysql Select, Update i Delete w jednym zapytaniu?

  5. Zmiana wygenerowanej nazwy klucza obcego w Hibernate