2010-08-13 45 views
11

J'ai un tableau T1, il contient une valeur NOM (non unique), et une plage de dates (D1 et D2 qui sont des dates) Lorsque NOM sont identiques, nous faisons une union de la date gammes (par exemple B).ORACLE SQL Entrées de la plage de dates

Mais comme résultat (X), nous devons faire intersection de toutes les plages de dates

Edit: Tableau T1

NAME | D1  | D2 
A | 20100101 | 20101211 
B | 20100120 | 20100415 
B | 20100510 | 201
C | 20100313 | 20100610 

Résultat:

X | 20100313 | 20100415 
X | 20100510 | 20100610 

Visuellement, cette donnera ce qui suit:

NAME  : date range 
A   : [-----------------------]----- 
B   : --[----]---------------------- 
B   : ----------[---------------]--- 
C   : -----[--------]--------------- 

Résultat:

X   : -----[-]---------------------- 
X   : ----------[---]--------------- 

Toute idée comment obtenir que l'utilisation de SQL/PL SQL?

+1

Vous pouvez essayer des chevauchements - mais il est fonction non documentée, http://oraclesponge.wordpress.com/2008/06/12/the-overlaps- prédicat/et ses seules vérifications que la plage de données a chevauché la période –

+0

Pouvez-vous afficher un exemple réel de colonne/ligne des valeurs de colonne de votre table et les valeurs de données que vous voulez renvoyer par cette requête SQL –

+0

Les intersections de date dans le résultat sont pour lequel deux noms? A et C sont des noms différents et les deux plages de B ne semblent pas avoir la plage de dates en question. –

Répondre

8

ici est une solution rapide (peut-être pas le plus efficace):

SQL> CREATE TABLE myData AS 
    2 SELECT 'A' name, date'2010-01-01' d1, date'2010-12-11' d2 FROM DUAL 
    3 UNION ALL SELECT 'B', date'2010-01-20', date'2010-04-15' FROM DUAL 
    4 UNION ALL SELECT 'B', date'2010-05-10', date'2010-12-30' FROM DUAL 
    5 UNION ALL SELECT 'C', date'2010-03-13', date'2010-06-10' FROM DUAL; 

Table created 

SQL> WITH segments AS (
    2 SELECT dat seg_low, lead(dat) over(ORDER BY dat) seg_high 
    3 FROM (SELECT d1 dat FROM myData 
    4   UNION 
    5   SELECT d2 dat FROM myData) 
    6 ) 
    7 SELECT s.seg_low, s.seg_high 
    8 FROM segments s 
    9 JOIN myData m ON s.seg_high > m.d1 
10     AND s.seg_low < m.d2 
11 GROUP BY s.seg_low, s.seg_high 
12 HAVING COUNT(DISTINCT NAME) = 3; 

SEG_LOW  SEG_HIGH 
----------- ----------- 
13/03/2010 15/04/2010 
10/05/2010 10/06/2010 

Je construis toutes les plages de dates successives possibles et rejoindre ce « calendrier » avec les données d'échantillon. Ceci énumérera toutes les gammes qui ont 3 valeurs. Vous devrez peut-être fusionner le résultat si vous ajoutez des lignes:

SQL> insert into mydata values ('B',date'2010-04-15',date'2010-04-16'); 

1 row inserted 

SQL> WITH segments AS (
    2 SELECT dat seg_low, lead(dat) over(ORDER BY dat) seg_high 
    3 FROM (SELECT d1 dat FROM myData 
    4   UNION 
    5   SELECT d2 dat FROM myData) 
    6 ) 
    7 SELECT MIN(seg_low), MAX(seg_high) 
    8 FROM (SELECT seg_low, seg_high, SUM(gap) over(ORDER BY seg_low) grp 
    9    FROM (SELECT s.seg_low, s.seg_high, 
10       CASE 
11        WHEN s.seg_low 
12         = lag(s.seg_high) over(ORDER BY s.seg_low) 
13        THEN 0 
14        ELSE 1 
15       END gap 
16      FROM segments s 
17      JOIN myData m ON s.seg_high > m.d1 
18         AND s.seg_low < m.d2 
19      GROUP BY s.seg_low, s.seg_high 
20     HAVING COUNT(DISTINCT NAME) = 3)) 
21 GROUP BY grp; 

MIN(SEG_LOW) MAX(SEG_HIGH) 
------------ ------------- 
13/03/2010 16/04/2010 
10/05/2010 10/06/2010 
+0

Exactement ce dont j'avais besoin! Merci encore Vincent;) je suppose que je pourrais remplacer "3" par (sélectionner le nombre (distinct NAME) de myData)? – guigui42

+0

Je viens de voir votre EDIT, et je ne comprends pas vraiment ce que vous entendez par "si j'ajoute une ligne". Dans ma table de données, je pourrais avoir des noms illimités (par exemple ABCDEFG ...) chacun pourrait avoir des lignes dupliquées (1, 2 lignes ou plus avec le même nom) avec des plages de dates consécutives (pas de chevauchement, mais mon exemple B). Alors, votre deuxième extrait de code fonctionnera-t-il pour tous ces cas? J'essaie toujours de comprendre comment vos analystes fonctionnent dans votre requête. Merci encore ! – guigui42

+0

@ guigui42: la première requête sera correcte, mais le résultat peut contenir des intervalles consécutifs (par exemple dans ce cas «2010-03-13 2010-04-15» et «2010-04-15 2010-04-16») . La deuxième requête fusionnera ces intervalles. –