2015-09-15 24 views
5

Desidero utilizzare uno FULL OUTER JOIN tra due tabelle su più colonne, ma quando entrambe le colonne sono nulle, non sono considerate uguali durante il join, quindi ottengo due righe diverse. Come posso scrivere il mio join, quindi le colonne null sono considerate uguali?SQL: FULL OUTER JOIN su colonne null

ho predisposto un esempio semplificato:

create table t1 (
id number(10) NOT NULL, 
field1 varchar2(50), 
field2 varchar2(50), 
CONSTRAINT t1_pk PRIMARY KEY (id) 
); 

create table t2 (
    id number(10) NOT NULL, 
    field1 varchar2(50), 
    field2 varchar2(50), 
    extra_field number(1), 
    CONSTRAINT t2_pk PRIMARY KEY (id) 
); 

insert into t1 values(1, 'test', 'test2'); 
insert into t2 values(1, 'test', 'test2', null); 

insert into t1 values(2, 'test1', 'test1'); 
insert into t2 values(2, 'test1', 'test1', null); 

insert into t1 values(3, 'test0', null); 
insert into t2 values(3, 'test0', null, 1); 

insert into t2 values(4, 'test4', 'test0', 1); 

select * 
from t1 
full outer join t2 using (id, field1, field2); 

risultato ottenuto: enter image description here

Risultato atteso: enter image description here

SQLFiddle

+0

Perché non limitarsi a unirsi sulle colonne ID poiché sono entrambe chiavi principali per le rispettive tabelle? – Sentinel

risposta

1

Usa NVL() e una stringa univoca per sostituire NULL:

select t1.id,t1.field1,t1.field2,t2.extra_field 
from t1 
full outer join t2 ON 
t1.id=t2.id 
AND NVL(t1.field1,'UID_INSTEAD_OF_NULL')=NVL(t2.field1,'UID_INSTEAD_OF_NULL') 
AND NVL(t1.field2,'UID_INSTEAD_OF_NULL')=NVL(t2.field2,'UID_INSTEAD_OF_NULL') 
proprio codice

SQLFiddle demo

+1

Questa soluzione perde qualsiasi vantaggio di indici su campo1 e/o campo2 a meno che non si definiscano indici basati su funzione – Sentinel

0

I risultati non rendono facile distinguere un NULL nei dati da un NULL che rappresenta un errore di adesione. Quando i valori nulli sono presenti nei dati che vengono uniti, di solito è preferibile ometterli dai risultati utilizzando un join regolare. Vedi questo link: https://technet.microsoft.com/en-us/library/ms190409(v=sql.105).aspx

select * 
from t1, t2 
where t1.id = t2.id and t1.field1 = t2.field1 and t1.field2 = t2.field2; 
0

Una soluzione è quella di utilizzare NVL e convertire NULL in un valore scalare.

select * 
from t1 
full outer join t2 
    ON NVL(t1.id, 0) = NVL(t2.id, 0) 
    AND NVL(t1.field1, 0) = NVL(t2.field1, 0) 
    AND NVL(t1.field2, 0) = NVL(t2.field2, 0) 
; 
+1

Tutti gli indici vanno persi a meno che non vengano creati indici basati su funzioni corrispondenti – Sentinel

+1

@Sentinel Sì, è corretto. –

0

internamente di Oracle (per rinfrescare viste materializzate, per esempio) si avvale della Sys_Op_Map_NonNull () per questo, che renderebbe il tuo join:

select * 
from t1 
full outer join t2 on (t1.id       = t2.id and 
         t1.field1      = t2.field2 and 
         Sys_Op_Map_NonNull(t1.field2) = Sys_Op_Map_NonNull(t2.field2)); 

Non sono sicuro che il suo utilizzo sia ufficialmente supportato, o se hanno iniziato a documentarlo pubblicamente.

+0

soluzione molto interessante, grazie – bviale

2

NVL può essere applicato sul risultato quindi nessuna funzione è necessario nella condizione di join

select 
    nvl(t1.id, t2.id) id, 
    nvl(t1.field1, t2.field1) field1, 
    nvl(t1.field2, t2.field2) field2, 
    extra_field 
from t1 
full outer join t2 on t1.id = t2.id AND t1.field1 = t2.field1 AND (t1.field2 = t2.field2 OR (t1.field2 IS NULL AND t2.field2 IS NULL)); 
+1

Questa è una buona soluzione. – Sentinel

+0

Ho dovuto aggiornare la mia domanda in posti con risposta Husqvik (come richiesto alla risposta VALEX fornita). Ho notato tuttavia che Sentinels ha commentato di aver perso il vantaggio dell'indicizzazione. Ho avuto solo 300 righe. Ma è bello saperlo. Grazie a tutti! – ionescu77

0

Questa soluzione mantiene l'uso della clausola usare, ma elimina l'una colonna nella clausola utilizzando contenente valori nulli (field2). Invece il campo 2 è unito nell'elenco di selezione.

select id 
    , field1 
    , coalesce(t1.field2,t2.field2) field2 
    , extra_field 
from t1 
full outer join t2 using (id, field1); --field2 removed from using clause.