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

Пребройте броя на последователните посещения

Пропуснах тага mysql и написах това решение. За съжаление, това не работи в MySQL, тъй като не поддържа функции на прозорци .

Все пак го публикувам, тъй като положих малко усилия. Тестван с PostgreSQL. Ще работи по подобен начин с Oracle или SQL Server (или всяка друга прилична RDBMS, която поддържа функции на прозорци).

Тестова настройка

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

Опростена версия

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

Изход:

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

По-бързо/по-кратко

По-късно намерих още по-добър начин. grp числата не са непрекъснати (а непрекъснато нарастват). Няма значение, тъй като те са само средство за постигане на цел:

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;

SQL Fiddle и за двете.

Още



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Свързване с множество CloudSQL екземпляри с помощта на Cloud sql прокси?

  2. Възможно ли е да се вмъкнат данни в изглед на MySQL?

  3. Данни от колоната на обобщената таблица на MySQL като редове

  4. 2 функции, които връщат името на месеца от дата в MySQL

  5. php вмъкването на база данни не работи според плана