2017-03-14 3 views
1

Datenbank my_table:Oracle SQL Überschneidungen zwischen Beginn und Enddatum in 2 oder mehreren Datensätze

id  seq  start_date  end_date 
1  1  01-01-2017  02-01-2017 
1  2  07-01-2017  09-01-2017 
1  3  11-01-2017  11-01-2017 
2  1  20-01-2017  20-01-2017 
3  1  01-02-2017  02-02-2017 
3  2  03-02-2017  04-02-2017 
3  3  08-01-2017  09-02-2017 
3  4  09-01-2017  10-02-2017 
3  5  10-01-2017  12-02-2017 

Meine Forderung ist das erste Datum (in der Regel seq 1 Startdatum) und Enddatum (normalerweise letztes Seq Ende zu bekommen Datum) und die Anzahl der Daten, die während aller seq für jede eindeutige ID aufgetreten sind.

eingetreten:

id  1    2    3 
     01-01-2017  20-01-2017  01-02-2017 
     02-01-2017     02-02-2017 
     07-01-2017     03-02-2017 
     08-01-2017     04-02-2017 
     09-01-2017     08-02-2017 
     11-01-2017     09-02-2017 
             10-02-2017 
             11-02-2017 
             12-02-2017 
total 6    1    9 

Hier ist das Ergebnis Ich möchte:

id  start_date  end_date  num_date 
1  01-01-2017  11-01-2017  6 
2  20-01-2017  20-01-2017  1 
3  01-02-2017  12-02-2017  9 

I

SELECT id 
     , MIN(start_date) 
     , MAX(end_date) 
     , SUM(end_date - start_date + 1) 
FROM  my_table 
GROUP BY id 

und diese SQL-Anweisung funktionieren in id 1 und 2 versucht haben seit Es gibt kein Überschneidungsdatum zwischen Anfangsdatum und Enddatum. Aber für ID 3 ist das Ergebnis num_date 11. Könnten Sie bitte die SQL-Anweisung vorschlagen, um dieses Problem zu lösen? Vielen Dank. Eine weitere Frage: Das Datum in der Datenbank ist in datetime Format. Wie konvertiere ich es in date. Ich habe versucht, TRUNC Funktion zu verwenden, aber es manchmal Datum zu gestern umwandeln. enter image description here

+0

Ist das die einzige Art möglich überlappen das Enddatum eines Intervalls gleich dem Startdatum der nächsten in Ihrer Daten? Oder können sich zwei Intervalle für mehr als einen Tag überschneiden? – mathguy

+0

Es wird keine Überschneidungsintervalle geben. – lvlack

+1

Können Sie ein Beispiel angeben, bei dem TRUNC ein Datum mit Uhrzeit auf GESTERN kürzt? Ich habe das nie gesehen (und ehrlich gesagt glaube ich es nicht). – mathguy

Antwort

1

Sie müssen zählen, wie oft ein end_date dem folgenden start_date entspricht. Dazu müssen Sie die Analysefunktion lag() oder lead() verwenden. Sie können einen case Ausdruck für den Vergleich verwenden, aber leider können Sie den case Ausdruck innerhalb einer COUNT oder in derselben Abfrage nicht umbrechen; Sie benötigen eine Unterabfrage und eine äußere Abfrage.

So etwas wie das; nicht getestet, da Sie CREATE TABLE- und INSERT-Anweisungen nicht zur Verfügung gestellt haben, um Ihre Beispieldaten neu zu erstellen.

select id, min(start_date) as start_date, max(end_date) as end_date, 
     sum(end_date - start_date + 1 - flag) as num_days 
from  (select id, start_date, end_date, 
        case when start_date = lag(end_date) 
          over (partition by id order by end_date) then 1 
                    else 0 end as flag 
      from my_table 
     ) 
group by id; 
0
SELECT id, 
     MIN(start_date) AS start_date, 
     MAX(end_date) AS end_date, 
     SUM(end_date - start_date + 1) AS num_days 
FROM (
    SELECT id, 
     GREATEST(
      start_date, 
      COALESCE(
      LAG(end_date) OVER (PARTITION BY id ORDER BY seq) + 1, 
      start_date 
      ) 
     ) AS start_date, 
     end_date 
    FROM your_table 
) 
WHERE start_date <= end_date 
GROUP BY id; 
+0

Das OP zählt nicht die Anzahl der einzelnen Elemente; Er zählt alle Tage zwischen start_date und end_date. Das können 8 Tage sein, aber die Anzahl wird nur 2 sein. – mathguy

+0

Ein anderer Gedanke (der hier nicht verwandt ist, denn für das, was Sie vorschlagen, brauchen Sie "UNION" und nicht "UNION ALL") - um einen nicht normalen Tisch mit "UNION ALL" zu "normalisieren", ist es effizienter zu "UNPIVOT", Da muss die Basistabelle nur einmal gelesen werden. Gerade habe ich das vor kurzem selbst gelernt und es ist in der Tat eine signifikante Verbesserung. – mathguy

Verwandte Themen