Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL konsolidiert Tabellenzeilen mit überlappenden Datumsspannen

Eine Möglichkeit, dies zu tun, ist die Verwendung von korrelierten Unterabfragen:

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

Das WHERE Prädikate der korrelierten Unterabfragen:

t2.opens <= t1.closes AND t2.closes >= t1.opens

gibt alle überlappenden Datensätze zurück, die sich auf den aktuellen Datensatz beziehen. Durch die Aggregation dieser Datensätze können wir die Start- und Enddaten jedes Intervalls finden:Das Startdatum des Intervalls ist das Minimum opens Datum zwischen allen überlappenden Datensätzen, wobei das Enddatum das Maximum closes ist Datum.

Demo hier

BEARBEITEN:

Die obige Lösung funktioniert nicht mit Intervallen wie den folgenden:

1. |-----------|
2. |----|
3.           |-----|

Rekord-Nr. 2 erzeugt bei der Verarbeitung ein fehlerhaftes Start-/Endintervall.

Hier ist eine Lösung mit Variablen:

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

Die Idee ist, ganz links opens/closes zu beginnen Intervall. Variablen @start , @end werden verwendet, um das inkrementell expandierende (wenn neue überlappende Zeilen verarbeitet werden) konsolidierte Intervall entlang der Intervallkette weiterzugeben. Sobald ein nicht überlappendes Intervall gefunden wird, [@start - @end] wird initialisiert, um mit diesem neuen Intervall und grp übereinzustimmen wird um eins erhöht.

Demo hier