- SQL
- PL/SQL
- DBA
- Developer / Forms
- Developer / Reports
- Developer / Graphics
- Data-Warehouse

 
 
 

 
> Tutorials SQL
 

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.