======Alte Version====== Nun, diese Version ist eigentlich schon richtig. Aber viel zu kompliziert. Aber da ich mir soviel Mühe gab wollte ich nicht einfach alles löschen SELECT p1.*, p2.* FROM tbl_periode_1 AS p1, tbl_periode_2 AS p2 WHERE -- Start von P2 ist innerhalb von p1 (p2.start_2 BETWEEN p1.start_1 AND p1.end_1) -- Ende von P2 ist innerhalb von p1 OR (p2.end_2 BETWEEN p1.start_1 AND p1.end_1) -- p2 ist Grösser als p1 und p2 beginnt vor und endet nach p1 OR (p2.start_2 <= p1.start_1 AND p1.end_1 <= p2.end_2) ORDER BY p2.id_2, p1.id_1 ====Formel==== Ich verwende dazu die folgende Logik [Länge von P1] = [Ende 1] - [Start 1] + 1 [Differenz der Starts] = Wenn([Start 2] nach [Start 1] dann ([Start 2] - [Start 1])) sonst 0 [Differenz der Enden] = Wenn([Ende 2] vor [Ende 1] dann ([Ende 1] - [Ende 2])) sonst 0 [Anzahl Tage] = [Länge von P1] - [Differenz der Starts] - [Differenz der Enden] [Anzahl Tage] = [Anzahl Tage] grösser als 0 dann [Anzahl Tage] sonst 0 ====Grafische Darstellung zum Verständnis==== um die Logik etwas grafisch darzustellen, hier eine Tabelle mit den Fällen. In den Zeilen [Differenzen] sieht man die Umsetzung der Formeln [Differenz der Starts] und [Differenz der Enden]. In der Spalte [Days] dementsprechend die Umsetzung der Formeln für [Anzahl Tage] |?| Überschneidungen der Perioden || |[| || ||(x:7) @@Tage@@ || || |=| |=|{width: 70px} 1 |=|{width: 70px} 2 |=|{width: 70px} 3 |=|{width: 70px} 4 |=|{width: 70px} 5 |=|{width: 70px} 6 |=|{width: 70px} 7 |=| days || |#| |=| Periode 1 || || ||(x:3){background-color:red; border-left-width:thick; border-left-color:black; border-right-width:thick; border-right-color:black;} || || || **3** || |=|(x:9) Periode 2 ist innerhalb der Periode 1 || || Periode 2 || || ||{border-left-width:thick; border-left-color:black;} ||{background-color:yellow;} || ||{border-left-width:thick; border-left-color:black;} || || || || Differenzen || || ||{background-color:grey; border-left-width:thick; border-left-color:black;} **1** || ||{background-color:grey;} **1** ||{border-left-width:thick; border-left-color:black;} || || 3-1-1|| || Schnittperiode || || ||{border-left-width:thick; border-left-color:black;} ||{background-color:green;} || ||{border-left-width:thick; border-left-color:black;} || || **1** || |=|(x:9) Periode 2 beginnt vor und endet in der Periode || || Periode 2 || ||{background-color:yellow;} ||(x:2){background-color:yellow; border-left-width:thick; border-left-color:black;} || ||{border-left-width:thick; border-left-color:black;} || || || || Differenzen || ||||{border-left-width:thick; border-left-color:black;} || ||{background-color:grey;} **1** ||{border-left-width:thick; border-left-color:black;} || || 3-1|| || Schnittperiode || || ||(x:2){background-color:green; border-left-width:thick; border-left-color:black;} ||||{border-left-width:thick; border-left-color:black;} || || **2** || |=|(x:9) Periode 2 beginnt innerhalb und endet nach der Periode 1 || || Periode 2 || || ||{border-left-width:thick; border-left-color:black;}||(x:2){background-color:yellow; border-right-width:thick; border-right-color:black;} ||{background-color:yellow;} || || || || Differenzen || || ||{background-color:grey; border-left-width:thick; border-left-color:black;} **1** || || ||{border-left-width:thick; border-left-color:black;} || || 3-1|| || Schnittperiode || || ||{border-left-width:thick; border-left-color:black;} ||(x:2){background-color:green;} ||{border-left-width:thick; border-left-color:black;} || || **2** || |=|(x:9) Periode 2 beginnt vor und endet nach der Periode 1 || || Periode 2 || ||{background-color:yellow;} ||(x:3){background-color:yellow; border-left-width:thick; border-left-color:black; border-right-width:thick; border-right-color:black;} ||{background-color:yellow;} || || || || Differenzen || || ||{border-left-width:thick; border-left-color:black;} || || ||{border-left-width:thick; border-left-color:black;} || || 3 || || Schnittperiode || || ||(x:3){background-color:green; border-left-width:thick; border-left-color:black;} ||{border-left-width:thick; border-left-color:black;} || || **3** || |=|(x:9) Periode 2 ist vor der Periode 1 || || Periode 2 ||{background-color:yellow;} || ||{border-left-width:thick; border-left-color:black;} || || ||{border-left-width:thick; border-left-color:black;} || || || || Differenzen || ||{background-color:grey;} **4** ||(x:3){background-color:grey; border-left-width:thick; border-left-color:black;} ||{border-left-width:thick; border-left-color:black;} || || 3-4 || || Schnittperiode || || ||{border-left-width:thick; border-left-color:black;} || || ||{border-left-width:thick; border-left-color:black;} || || **0** || |=|(x:9) Periode 2 ist nach der Periode 1 || || Periode 2 || || ||{border-left-width:thick; border-left-color:black;} || || ||{border-left-width:thick; border-left-color:black;} ||{background-color:yellow;} || || || Differenzen || || ||(x:3){background-color:grey; border-left-width:thick; border-left-color:black; border-right-width:thick; border-right-color:black;} **4** ||{background-color:grey;} || || 3-4 || || Schnittperiode || || ||{border-left-width:thick; border-left-color:black;} || || ||{border-left-width:thick; border-left-color:black;} || || **0** || ====SQL Statement==== Und in SQL umgesetzt, könnte das etwa so aussehen SELECT id_1, start_1, end_1, id_2, start_2, end_2, days, start_date, end_date FROM ( -- Die eigentliche Berechnung: SELECT -- Beide Perioden auslesen p1.id_1, p1.start_1, p1.end_1, p2.id_2, p2.start_2, p2.end_2, -- Länge der Periode 1 berechnen. -- [[Länge von P1] = [Ende 1] - [Start 1] + 1 @p1_length := DATEDIFF(p1.end_1, p1.start_1) + 1 AS p1_length, -- Nur die positiven Differenzen zwieschen den Starts übernehmen -- [Differenz der Starts] = Wenn([Start 2] nach [Start 1] dann ([Start 2] - [Start 1])) sonst 0 @diff_start := GREATEST(DATEDIFF(p2.start_2, p1.start_1), 0) AS diff_start, -- Nur die positiven Differenzen zwieschen den Enden übernehmen -- [[Differenz der Enden] = Wenn([Ende 2] vor [Ende 1] dann ([Ende 1] - [Ende 2])) sonst 0 @diff_end := GREATEST(DATEDIFF(p1.end_1, p2.end_2) , 0) AS diff_end, -- übereinstimmende Länge berechnen (uns interessieren nur positive Längen): -- [Anzahl Tage] = [Länge von P1] - [Differenz der Starts] - [Differenz der Enden] -- [Anzahl Tage] = [Anzahl Tage] grösser als 0 dann [Anzahl Tage] sonst 0 @days := GREATEST((@p1_length - @diff_start - @diff_end), 0) AS days, -- Start und Endzeit von der Resultat-Periode berechnen IF(@days > 0, GREATEST(p2.start_2, p1.start_1) , NULL) AS start_date, IF(@days > 0, LEAST(p2.end_2, p1.end_1) , NULL) AS end_date FROM tbl_periode_1 AS p1, tbl_periode_2 AS p2 ) AS all_data WHERE days > 0 ORDER BY id_1, id_2; ====Resultat==== Und das ist das Resultat mit unseren Beispieldaten |?| Schnittperioden || ||(x:3) Periode 1 ||(x:3) Periode 2 ||(x:3) Schnittperiode || |=| id_1 |=| start_1 |=| end_1 |=| id_2 |=| start_2 |=| end_2 |=| days |=| start_date |=| end_date || || 1 || 2012-02-01 || 2012-02-28 || 2 || 2012-02-15 || 2012-02-15 || 1 || 2012-02-15 || 2012-02-15 || || 1 || 2012-02-01 || 2012-02-28 || 3 || 2012-01-01 || 2012-02-02 || 2 || 2012-02-01 || 2012-02-02 || || 1 || 2012-02-01 || 2012-02-28 || 4 || 2012-01-01 || 2012-12-31 || 28 || 2012-02-01 || 2012-02-28 || || 2 || 2012-02-15 || 2012-03-15 || 2 || 2012-02-15 || 2012-02-15 || 1 || 2012-02-15 || 2012-02-15 || || 2 || 2012-02-15 || 2012-03-15 || 4 || 2012-01-01 || 2012-12-31 || 30 || 2012-02-15 || 2012-03-15 || || 3 || 2012-04-01 || 2012-04-15 || 1 || 2012-03-20 || 2012-04-02 || 2 || 2012-04-01 || 2012-04-02 || || 3 || 2012-04-01 || 2012-04-15 || 4 || 2012-01-01 || 2012-12-31 || 15 || 2012-04-01 || 2012-04-15 || ====SQL Statement ohne Variablen==== Hier noch eine Version ohne Variablen. Diese braucht man, wenn man eine View anlegen will. Auch ist diese Version sehr nahe an anderen Datenbanken als MySQL, so dass das Konzept auch auf anderen Plattformen etwa so funktionieren kann SELECT id_1, start_1, end_1, id_2, start_2, end_2, -- übereinstimmende Länge berechnen (uns interessieren nur positive Längen): -- [Anzahl Tage] = [Länge von P1] - [Differenz der Starts] - [Differenz der Enden] -- [Anzahl Tage] = [Anzahl Tage] grösser als 0 dann [Anzahl Tage] sonst 0 GREATEST((p1_length - diff_start - diff_end), 0) AS days, CASE WHEN end_date >= start_date THEN start_date ELSE NULL END AS start_date, CASE WHEN end_date >= start_date THEN end_date ELSE NULL END AS end_date FROM ( SELECT -- Beide Perioden auslesen p1.id_1, p1.start_1, p1.end_1, p2.id_2, p2.start_2, p2.end_2, -- Länge der Periode 1 berechnen. -- [[Länge von P1] = [Ende 1] - [Start 1] + 1 DATEDIFF(p1.end_1, p1.start_1) + 1 AS p1_length, -- Nur die positiven Differenzen zwieschen den Starts übernehmen -- [Differenz der Starts] = Wenn([Start 2] nach [Start 1] dann ([Start 2] - [Start 1])) sonst 0 GREATEST(DATEDIFF(p2.start_2, p1.start_1), 0) AS diff_start, -- Nur die positiven Differenzen zwieschen den Enden übernehmen -- [[Differenz der Enden] = Wenn([Ende 2] vor [Ende 1] dann ([Ende 1] - [Ende 2])) sonst 0 GREATEST(DATEDIFF(p1.end_1, p2.end_2) , 0) AS diff_end, -- Start und Endzeit von der Resultat-Periode berechnen GREATEST(start_2, start_1) AS start_date, LEAST(end_2, end_1) AS end_date FROM tbl_periode_1 AS p1, tbl_periode_2 AS p2 ) AS prepared_data ORDER BY id_1, id_2;