2016-06-02 8 views
-4

Einfaches Beispiel Daten für Klarheit mit:nächste Werte finden SQL mit Datum diff

PERSON_PINCODE 

PERSON  START_DATE END_DATE PINCODE 
10023541700000 01-01-12 31-03-12 6059  
10023541700000 01-01-12 31-03-12 6060 

PINCODE_VALUE 

PINCODE START_DATE END_DATE VAR  VALUE 
6059 01-04-11 30-06-11 3889 28.4 
6059 01-07-11 30-09-11 3889 28.2 
6059 01-10-11 31-12-11 3890 31.4 
6060 01-04-11 30-06-11 3889 29.4 
6060 01-07-11 30-09-11 3889 41.2 
6060 01-10-11 31-12-11 3890 43.4 

Output should be: 

PERSON_PINCODE_VALUE

PERSON   START_DATE END_DATE PINCODE VAR VALUE DIFF 
10023541700000 01-01-12 31-03-12 6059  3889 28.2 90 days 
10023541700000 01-01-12 31-03-12 6059  3890 31.4 1 day 
10023541700000 01-01-12 31-03-12 6060  3890 41.2 90 days 
10023541700000 01-01-12 31-03-12 6060  3890 43.4 1 day 

Um PERSON_PINCODE_VALUE zu bekommen,

wie folgt vor:

1) Take each row of PERSON_PINCODE and find PINCODE, START_DATE, END_DATE 
2) For each PINCODE from step 1, find START_DATE, END_DATE, VAR, VALUE from PINCODE_VALUE 
3) Associate all values from step 1 and step 2, on the basis of PINCODE, START_DATE and END_DATE 
4) If in step 3, we do NOT get exact PINCODE, START_DATE and END_DATE for each VAR from step 2, find nearest prior START_DATE for remaining VAR 
5) Associate values from step 4 with DIFF as PERSON_PINCODE.START_DATE - PINCODE_VALUE.END_DATE 
+0

Bitte teilen Sie das Skript Sie versucht –

+0

Der Einfachheit halber können Sie nummerieren alle Personen 1, 2, 3, 4, 5, etc. Auch für Person '10025868900000' wie Hast du dieses Start- und Enddatum und warum hast du doppelte Zeilen mit verschiedenen 'Pincodes'? – MT0

+0

Auch für die Person '10023541700000' wenn Sie 'DATUM' 2012-01-01 '- DATUM' 2011-07-01'' haben, erhalten Sie 184 Tage - wie erhalten Sie einen Unterschied von 90 Tagen? – MT0

Antwort

0

hier ein „konventionelleren“ -Ansatz mit einer Verknüpfung aller Zeilen und Filtern die beste Übereinstimmung mit der ROW_NUMBER

with hlpr as (
select pp.PERSON, pp.START_DATE, pp.END_DATE, pp.PINCODE, 
pv.START_DATE PV_START_DATE, pv.END_DATE PV_END_DATE, 
pv.VALUE, pv.VAR, 
pp.START_DATE - pv.END_DATE as diff, 
row_number() over(partition by pp.PERSON, pp.START_DATE, pp.END_DATE, pp.PINCODE, pv.VAR 
    order by pp.START_DATE - pv.END_DATE) as rn 
from PERSON_PINCODE pp 
join PINCODE_VALUE pv on pp.PINCODE = pv.PINCODE 
where pp.START_DATE >= pv.END_DATE /* prior PV only */ 
) 
select /*+ PARALLEL(5) */ PERSON, START_DATE, END_DATE, PINCODE, VAR,VALUE, DIFF 
from hlpr 
where rn = 1 
order by 1,2,3,4; 

gibt

PERSON   START_DATE  END_DATE    PINCODE  VAR  VALUE  DIFF 
-------------- ----------------- ----------------- ---------- ---------- ---------- ---------- 
10023541700000 01.01.12 00:00:00 31.03.12 00:00:00  6059  3889  28,2   93 
10023541700000 01.01.12 00:00:00 31.03.12 00:00:00  6059  3890  31,4   1 
10023541700000 01.01.12 00:00:00 31.03.12 00:00:00  6060  3889  41,2   93 
10023541700000 01.01.12 00:00:00 31.03.12 00:00:00  6060  3890  43,4   1 

ich diese Lösung bevorzugen würde, wenn die Abfrage eine hat große Anzahl von Attributen (da die Ordnungslogik an einer Stelle konzentriert ist).

Nur für eine große Datenmenge würde ich die GROUP BY-Methode von @ MT0 verwenden, da die SORT GROUP BY im Allgemeinen besser funktioniert als die WINDOW SORT.

Hier werden die Beispieldaten

create table PERSON_PINCODE as 
select '10023541700000' PERSON, to_date('01-01-12','dd-mm-rr') START_DATE, to_date('31-03-12','dd-mm-rr') END_DATE, 6059 PINCODE from dual union all 
select '10023541700000' PERSON, to_date('01-01-12','dd-mm-rr') START_DATE, to_date('31-03-12','dd-mm-rr') END_DATE, 6060 PINCODE from dual 
; 

create table PINCODE_VALUE as 
select 6059 PINCODE, to_date('01-04-11','dd-mm-rr') START_DATE, to_date('30-06-11','dd-mm-rr') END_DATE, 3889 VAR, 28.4 VALUE from dual union all 
select 6059 PINCODE, to_date('01-07-11','dd-mm-rr') START_DATE, to_date('30-09-11','dd-mm-rr') END_DATE, 3889 VAR, 28.2 VALUE from dual union all 
select 6059 PINCODE, to_date('01-10-11','dd-mm-rr') START_DATE, to_date('31-12-11','dd-mm-rr') END_DATE, 3890 VAR, 31.4 VALUE from dual union all 
select 6060 PINCODE, to_date('01-04-11','dd-mm-rr') START_DATE, to_date('30-06-11','dd-mm-rr') END_DATE, 3889 VAR, 29.4 VALUE from dual union all 
select 6060 PINCODE, to_date('01-07-11','dd-mm-rr') START_DATE, to_date('30-09-11','dd-mm-rr') END_DATE, 3889 VAR, 41.2 VALUE from dual union all 
select 6060 PINCODE, to_date('01-10-11','dd-mm-rr') START_DATE, to_date('31-12-11','dd-mm-rr') END_DATE, 3890 VAR, 43.4 VALUE from dual; 
+0

Diese Lösung funktioniert nicht, denn wenn jedem PINCODE mehrere VAR zugeordnet sind, wird nur ein VAR zugewiesen. Wenn es eine genaue Übereinstimmung zwischen dem Datum gibt, wird die Verzögerung als 1 oder 89 berechnet, während es 0 sein sollte. – dang

+0

@dang Redigiert zu den neuen Bedingungen –

0
SELECT p.person, 
     p.start_date, 
     p.end_date, 
     p.pincode, 
     v.var, 
     MAX(v.value) 
        KEEP (DENSE_RANK FIRST ORDER BY ABS(v.start_date - p.start_date)) 
        AS value, 
     DECODE(
      MIN(ABS(v.start_date - p.start_date)), 
      0, 0, 
      MIN(ABS(p.start_date - v.end_date)) 
        KEEP (DENSE_RANK FIRST ORDER BY ABS(p.start_date - v.start_date)) 
     ) AS diff 
FROM  Person_Pincode p 
     INNER JOIN 
     Pincode_Value v 
     ON (p.pincode = v.pincode) 
GROUP BY p.person, 
     p.start_date, 
     p.end_date, 
     p.pincode, 
     v.var; 
+0

Schöne Lösung mit 'KEEP' –

+0

der Wert für VAR ist falsch, weil Sie MAX-Wert verwenden, wird dies nicht funktionieren. Diff ist auch falsch. – dang

+0

@dang Nur zu sagen, dass es falsch ist, das Problem nicht konstruktiv zu beheben. Bitte sagen Sie mir ** warum ** es ist falsch - möglicherweise mit einigen Beispielrechnungen, um das Problem zu veranschaulichen (und wenn möglich, was getan werden könnte, um es zu korrigieren). – MT0

Verwandte Themen