Oracle 9i - Join
di Mirco Grieco
Con l'avvento di Oracle 9i molte cose
sono cambiate nelle potenzialità di Oracle. Una di queste riguarda
sicuramente un nuovo modo di effettuare delle query su più tabelle
(JOIN).
Ripasso delle Join
Una JOIN è un tipo di query che permette
di selezionare i dati da due o più tabelle o viste. La lista di
campi presenti nella select può essere composta da qualunque colonna
delle tabelle menzionate nella clausola from. Nel caso in cui
il riferimento ad una colonna utilizzata nella query sia ambiguo,
ovvero questa colonna sia presente col medesimo nome in più di
una tabella fra quelle presenti nella clausola from, occorre qualificare
tutti i riferimenti a queste colonne con i nomi della tabella
o alias per evitare ambiguità.
Esempio: SELECT tabA.campo_comune,
campoA1, campoB1 FROM tabellaA tabA, tabellaB
Con l'esempio precedente, otteniamo il "prodotto cartesiano" delle
due tabelle, ovvero ogni record della tabella tabellaA viene associato
con ogni record della tabella tabellaB ottenendo, come risultato,
una lista di tuple di numero pari al prodotto dei numeri di records
della prima tabella con il numero di records della seconda.
Esempio: se nA è il numero di records di tabellaA e
nB è il numero di records della tabellaB, la SELECT precedente
darà sicuramente come risultato una lista di nA * nB tuple.
Supponiamo ora che esista un nesso logico tra le tabelle coinvolte
dalla JOIN e che questo nesso sia stato codificato da una coppia
"chiave primaria - chiave esterna", per limitare il risultato
ottenuto alle sole "tuple significative", cioè quelle tuple che
sono il frutto dell'unione di record "coerenti" tra loro, occorre
aggiungere alla nostra select una "WHERE condition" detta "condizione
di join". Questa condizione di JOIN dovrà contenere in "AND" tutti
i campi che compongono la chiave primaria.
Esempio: se la chiave primaria di tabellaA è composta
da i campi CA1 e CA2 e la relativa chiave esterna di tabellaB
è composta da i campi CA1 e CA2 (per complicare un pochino le
cose supponiamo che abbiano lo stesso nome...) allora la WHERE
condition dovrà essere la seguente: tabellaA.CA1=tabellaB.CA1
and tabellaA.CA2=tabellaB.CA2
I campi messi a confronto in una Join condition non hanno bisogno
di essere inseriti nella lista prescelta (select).
In linea generale possiamo affermare che, date N tabelle in JOIN,
sono necessarie N-1 condizioni di join per evitare il prodotto
cartesiano e ottenere risultati coerenti.
Nel caso in cui ci siano tre o più tabelle sarà l'ottimizzatore
a determinare l'ordine con cui Oracle assocerà le tabelle tenendo
conto degl'indici e delle statistiche eventualmente collezionate
in precedenza con il comando ANALYZE TABLE.
Oltre alle condizioni di join la clausola where può contenere
altre condizioni (dette "di filtro") che si riferiscono alle colonne
delle tabelle selezionate. Queste circostanze possono ulteriormente
limitare il numero dei record ottenuti dalla query.
Inner e Outer Join
Una Inner join (chiamata semplicemente
join) è una join tra due o più tabelle che restituisce soltanto
quei record che soddisfano la condizione di join espresse nella
clausola di Where.
Esempio: Inner join tra due tabelle che hanno
i campi ID, nome e numero in relazione tra loro. La select avrà
il seguente aspetto:
SELECT tabA.id,tabA.nome FROM tabellaA tabA,tabellaB
tabB WHERE tabA.id = tabB.id AND tabA.nome = tabB.nome AND tabA.numero
= tabB.numero;
Una Outer join estende il risultato di un semplice join. Essa
ritorna tutti i record che soddisfano la condizione di join ed
inoltre restituisce tutti quei record di una tabella specificata
che sono presenti nella condizione di join ma che non hanno corrispondenza
nell'altra tabella.
Esempio : SELECT ename, job, dept.deptno,
dname FROM emp, dept WHERE emp.deptno (+) = dept.deptno AND job
(+) = 'CLERK';
|
ENAME
|
JOB
|
DEPTNO
|
DNAME
|
|
MILLER
|
CLERK
|
10
|
ACCOUNTING
|
|
SMITH
|
CLERK
|
20
|
RESEARCH
|
|
ADAMS
|
CLERK
|
20
|
RESEARCH
|
|
JAMES
|
CLERK
|
30
|
SALES
|
|
|
|
40
|
OPERATIONS
|
In questa outer join, Oracle ritorna
tutti i reparti, anche quelli in cui nessun impiegato lavora.
l'operatore (+) sulla colonna Job si accerta che le righe per
cui la colonna Jon è Null siano restituite. Se questo (+) fosse
omesso, le righe che contengono un valore significativo nella
colonna DNAME non sarebbero restituite perché il relativo valore
di Job non è 'CLERK'.
Mettiamo il caso di voler scrivere una query che effettua un'Outer
Join tra le tabelle A e B e ritorni tutti i record da A. Questo
risultato si ottiene usando la sintassi ANSI left outer join,
o applicando l'operatore (+) a tutte le colonne della tabella
B nella condizione di join.Per tutti i record in A che non hanno
corrispondenza in B, Oracle ritorna il valore Null.
Nel caso contrario si vuole scrivere una query ritorni tutti i
record da B il risultato si ottiene usando la sintassi ANSI right
outer join, o applicando l'operatore (+) a tutte le colonne della
tabella A nella condizione di join.Per tutti i record in B che
non hanno corrispondenza in A, Oracle ritorna il valore Null.
Nel caso in cui si volessero avere come ritorno i record di A
e di B occorre usare la sintassi ANSI full outer join.
Per quanto riguarda l'operatore (+) occorre sapere che ci sono
delle restrizioni.
Infatti l'operatore (+) può apparire solamente nella clausola
Where e può essere applicato soltanto ad una colonna di una tabella
o di una vista. Se le tabelle A e B hanno più condizioni di join,
occorre usare l'operatore (+) in tutte queste condizioni. Se ciò
non avviene Oracle restituirà soltanto i record che derivano da
un semplice join, ma non avvertirà l'utente di un eventuale errore.
L'operatore (+) può essere applicato soltanto ad una colonna,
e non ad un'espressione arbitraria. Tuttavia, un'espressione arbitraria
può contenere una colonna segnata con (+) l'operatore. Una condizione
che contiene l'operatore (+) non può essere unita con un'altra
condizione che usa l'operatore logico OR o l'operatore IN. Una
condizione non può avere una colonna contrassegnata con l'operatore
(+) confrontata con una subquery.
Nuova sintassi
La sintassi è stata, come prevedibile,
mutata, infatti, a partire dalla dichiarazione delle tabelle si
possono notare i primi cambiamenti.
- Vecchio standard ANSI : From
Proprietari a,Case b
- Nuovo standard ANSI : From Proprietari
a INNER JOIN Case b
Le differenze sono sostanzialmente due, la prima è il non utilizzo
della virgola per separare le due tabelle, la seconda prevede
l'utilizzo della parola chiave Inner Join che prima era omessa.
Quindi nella query al momento di dichiarare le tabelle è obbligatoria
specificare il tipo di join che verrà usata. Altre differenze
sono visibili se guardiamo bene queste due query:
- Vecchio standard ANSI : Select
a.id_proprietario, b.via From Proprietari a,Case b Where
a.id_proprietario = b.id_proprietario;
Come si nota nel vecchio standard non è presente nessuna parola
chiave nella condizione di FROM e la vera e propria condizione
di join è specificata nella condizione di WHERE dove i campi chiave
in relazione vengono eguagliati. Cosa succede nel nuovo standard
ANSI :
- Nuovo standard ANSI : Select
a.id_proprietario, b.via From Proprietari a inner join
Case b on a.id_proprietario = b.id_proprietario;
Succede che le condizioni di join non si trovano più nella clausola
where ma compaiono nella clausola from con le parole chiave Inner
Join e On. Che cosa comporta questo. Comporta che tutto
venga dichiarato in una sola parte, che le probabilità di prodotto
cartesiano diminuiscano,e non è più obbligatorio scriver complesse
clausole di Where.
Una volta digitata la parola chiave inner join sarà Oracle 9i
a richiedere la clausola On.
Possiamo ora sostituire la clausola ON con la clausola USING:
- Select a.id_proprietario, b.via
From Proprietari a inner join Case b Using (id_proprietario);
- Select a.id_proprietario,b.via
From PROPRIETARI a full outer join case b Using
(id_proprietario);
In questo caso Oracle 9i prenderà dalle due tabelle tutte le righe
in cui i valori dei due campi in relazione sono uguali.
Natural Join
Vi è ancora un'altra scorciatoia la
clausola Natural Join la quale associa tutte le colonne
delle due tabelle che hanno identico nome.
Qual è il problema della Natural Join?
Il problema consiste nell'uguaglianza dei nomi, se pensiamo che
ad un certo punto il nome di una delle due colonne identiche fosse
cambiato la natural join non avrebbe più efficacia. L'unica limitazione
della natural join è che non è possibile specificare una colonna
di tipo LOB o una colonna di una collection come componente di
una natural join.
- Select a.id_proprietario,b.via
From PROPRIETARI a natural inner join case b;
Multiple Join
Nel caso di join multiple Oracle 9i
di default processa queste da sinistra verso destra. E' possibile
controllare e modificare la sequenzialità di esecuzione delle
join tramite l'utilizzo delle parentesi.
- Select a.id_proprietario,b.via,c.cap
From (Proprietari a inner join Case b Using
(a.id_proprietario,b.via)) Inner join Citta c Using
(a.id_proprietario);
La prima join soddisfatta sarà tra le tabelle Proprietari e Case
e il risultato sarà messo in join nuovamente con la tabella Città.
Per concludere possiamo affermare che le modifiche apportate renderanno
più portabile il codice e sicuramente più facile da leggere anche
perché la join condition non è più nascosta tra le condizioni
di filtro ma è ben visibile nella dichiarazione delle tabelle.