Mysql
 sql >> Base de données >  >> RDS >> Mysql

MySQL consolidant les lignes de table avec des périodes de dates qui se chevauchent

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.

Démo ici

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.

Démo ici