Une façon de le faire est d'utiliser des sous-requêtes corrélées :
SELECT DISTINCT
(SELECT MIN(opens)
FROM mytable AS t2
WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS start,
(SELECT MAX(closes)
FROM mytable AS t2
WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS end
FROM mytable AS t1
ORDER BY opens
Le WHERE
prédicats des sous-requêtes corrélées :
t2.opens <= t1.closes AND t2.closes >= t1.opens
renvoie tous les enregistrements qui se chevauchent liés à l'enregistrement en cours. En effectuant l'agrégation de ces enregistrements, nous pouvons trouver les dates de début / fin de chaque intervalle :la date de début de l'intervalle est le minimum d'opens
date entre tous les enregistrements qui se chevauchent, alors que la date de fin est le maximum de closes
jour.
MODIF :
La solution ci-dessus ne fonctionnera pas avec un ensemble d'intervalles comme celui-ci :
1. |-----------|
2. |----|
3. |-----|
N° d'enregistrement 2, une fois traité, produira un intervalle de début/fin défectueux.
Voici une solution utilisant des variables :
SELECT MIN(start) AS start, MAX(end) AS end
FROM (
SELECT @grp := IF(@start = '1900-01-01' OR
(opens <= @end AND closes >= @start), @grp, @grp+1) AS grp,
@start := IF(@start = '1900-01-01', opens,
IF(opens <= @end AND closes >= @start,
IF (@start < opens, @start, opens), opens)) AS start,
@end := IF(@end = '1900-01-01', closes,
IF (opens <= @end AND closes >= @start,
IF (@end > closes, @end, closes), closes)) AS end
FROM mytable
CROSS JOIN (SELECT @grp := 1, @start := '1900-01-01', @end := '1900-01-01') AS vars
ORDER BY opens, DATEDIFF(closes, opens) DESC) AS t
GROUP BY grp
L'idée est de commencer par opens/closes
le plus à gauche intervalle. Variables @start
, @end
sont utilisés pour propager l'intervalle consolidé à expansion incrémentielle (lorsque de nouvelles lignes qui se chevauchent sont en cours de traitement) le long de la chaîne d'intervalles. Une fois qu'un intervalle sans chevauchement est rencontré, [@start - @end]
est initialisé pour correspondre à ce nouvel intervalle et grp
est incrémenté de un.