J'ai raté la balise mysql et j'ai écrit cette solution. Malheureusement, cela ne fonctionne pas dans MySQL car il ne prend pas en charge les fonctions de fenêtre .
Je le poste quand même, car j'y ai mis un peu d'effort. Testé avec PostgreSQL. Fonctionnerait de la même manière avec Oracle ou SQL Server (ou tout autre SGBDR décent prenant en charge les fonctions de fenêtre).
Configuration du test
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');
Version simplifiée
-- 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;
Sortie :
id | max_consecutive_days
--------+----------------------
444631 | 4
Plus rapide / Plus court
Plus tard, j'ai trouvé un moyen encore meilleur. grp
les nombres ne sont pas continus (mais augmentent continuellement). Peu importe, puisqu'il ne s'agit que d'un moyen :
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;
Plus
- Un solution procédurale
pour un problème similaire.
Vous pourrez peut-être implémenter quelque chose de similaire dans MySQL . - Réponses étroitement liées sur dba.SE avec une explication détaillée ici et ici .
- Et sur SO :
GROUP BY et valeurs numériques séquentielles agrégées