Join (SQL): differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Funzionalità collegamenti suggeriti: 2 collegamenti inseriti.
 
(136 versioni intermedie di 83 utenti non mostrate)
Riga 1:
{{F|programmazione|giugno 2018}}
Una <code>JOIN</code> è un comando [[SQL]] che serve a combinare le righe di due o più tabelle di un database. Lo standard ANSI definisce alcune specifiche per il linguaggio SQL sul tipo di <code>JOIN</code>da effettuare: <code>INNER</code>, <code>OUTER</code>, <code>LEFT</code> e <code>RIGHT</code>. In alcuni casi è possibile che una tabella possa essere combinata con se stessa, in questo caso si parlerà di ''self-join''.
 
La '''JOIN''' è una clausola del linguaggio [[SQL]] che serve a combinare le [[tuple]] di due o più [[Modello relazionale|relazioni]] di una [[base di dati]]. Lo standard [[ANSI]] definisce alcune specifiche per il linguaggio SQL sul tipo di JOIN da effettuare: {{Codice|codice=INNER JOIN|linguaggio=SQL}}, {{Codice|codice=FULL JOIN|linguaggio=SQL}}, {{Codice|codice=LEFT JOIN|linguaggio=SQL}} e {{Codice|codice=RIGHT JOIN|linguaggio=SQL}}, alle quali diversi [[DBMS]] aggiungono {{Codice|codice=CROSS JOIN|linguaggio=SQL}}. In alcuni casi è possibile che una tabella possa essere combinata con se stessa, in questo caso si parlerà di ''self-join''.
== Tabelle di esempio ==
 
== Tabelle di esempio ==
Tutti gli esempi che verranno riportati di seguito faranno uso delle seguenti due tabelle
Tutti gli esempi che verranno riportati di seguito faranno uso delle seguenti due tabelle:
 
{| class="wikitable" style="text-align:center; float:left; margin-right:5px"
Riga 20 ⟶ 21:
| Monti || 34
|-
| Grassi || {{null resultCodice|codice=NULL|linguaggio=SQL}}
|}
 
Riga 37 ⟶ 38:
|}
 
{{clear}}
<code>Dipartimenti.ID_dipartimento</code> è la [[chiave primaria]] che ha una [[cardinalità]] 0:n nei confronti del campo <code>Impiegati.ID_dipartimento</code>.
 
Nota: Il dipartimento <code>Promozione</code> della tabella <code>Dipartimenti</code> non ha alcuna corrispondenza nella tabella <code>Impiegati</code>. Mentre l'impiegato <code>Grassi</code> non è stato assegnato ad alcun dipartimento ([[NULL]]).
<code>Dipartimenti.ID_dipartimento</code> è la chiave primaria che ha una cardinalità 1:n nei confronti del campo <code>Impiegati.ID_dipartimento</code>
 
<br clear="all" />
 
Nota: Il dipartimento "Promozione" della tabella "Dipartimenti" non ha alcuna corrispondenza nella tabella "Impiegati". Mentre l'impegato "Grassi" non è stato assegnato ad alcun dipartimento ({{null result}}).
 
== Inner join ==
[[File:SQL Join - 07 A Inner Join B.svg|miniatura|[[Diagramma di Venn]] che rappresenta la {{Codice|codice=INNER JOIN|linguaggio=SQL}} di due tabelle]]
Una {{Codice|codice=INNER JOIN|linguaggio=SQL}} crea una nuova tabella combinando i valori delle due tabelle di partenza (<math>A</math> e <math>B</math>) basandosi su una certa regola di confronto. La query compara ogni riga della tabella <math>A</math> con ciascuna riga della tabella <math>B</math> cercando di soddisfare la regola di confronto definita. Quando la regola di join viene soddisfatta, i valori di tutte le colonne delle tabelle <math>A</math> e <math>B</math> vengono combinate in un'unica riga nella costruzione della tabella risultante. La {{Codice|codice=INNER JOIN|linguaggio=SQL}} è la forma di join usata più di frequente nelle applicazioni e rappresenta la modalità predefinita.
 
Per esempio, la seguente query unirà le due tabelle <code>Impiegati</code> e <code>Dipartimenti</code> usando la chiave primaria <code>ID_dipartimento</code> che è la colonna presente in entrambe le tabelle. Quando <code>ID_dipartimento</code> corrisponde in entrambe le tabelle (ovvero la regola è soddisfatta), la query combinerà le colonne <code>Cognome</code>, <code>ID_dipartimento</code> e <code>Nome_dipartimento</code> in un'unica riga per la tabella risultante.
Una inner join crea un nuova tabella combinando i valori delle due tabelle di partenza (A and B) basandosi su una certa regola di confronto. La query compara ogni riga della tabella A con ciascuna riga della tabella B cercando di soddisfare la regola di confronto definita. Quando la regola di join viene soddisfatta, i valori di tutte le colonne delle tabelle A e B vengono combinate in un'unica riga nella costruzione della tabella risultante. La inner join è la forma di join usata più di frequente nelle applicazioni e rappresenta la modalità di default.
 
Esempio di {{Codice|codice=INNER JOIN|linguaggio=SQL}} in forma esplicita:
Per esempio, la seguente query unirà le due tabelle 'Impiegati' e 'Dipartimenti' usando la chiave primaria 'ID_dipartimento' che è la colonna presente in entrambe le tabelle. Quando ID_dipartimento corrisponde in entrambe le tabelle (ovvero la regola è soddisfatta), la query combinerà le colonne ''Cognome'', ''ID_dipartimento'' e ''Nome_dipartimento'' in un'unica riga per la tabella risultante.
 
<syntaxhighlight lang="sql" line="1">
Esempio di inner join in forma esplicita:
<source lang=sql>
SELECT *
FROM Impiegati
INNER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
che equivale a:
 
<source lang=sql>
<syntaxhighlight lang="sql" line="1">
SELECT *
FROM Impiegati, Dipartimenti
WHERE Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
Risultato della query di Inner{{Codice|codice=INNER joinJOIN|linguaggio=SQL}}:
 
{| class="wikitable" style="text-align:center"
Riga 80 ⟶ 81:
|-
| Rossi || 31 || Vendite || 31
|-
|}
 
'''Nota''': l'impiegato "<code>Grassi"</code> e il dipartimento "<code>Promozione"</code> non sono presenti in quanto l'impiegato <code>Grassi</code> ha un {{null resultCodice|codice=NULL|linguaggio=SQL}} mentre <code>Promozione</code> non compare in nessun impiegato. A volte come risultato finale si desidera avere anche i campirecord che non hanno corrispondenza: in tal caso è possibile usare la query di tipo Outer{{Codice|codice=OUTER joinJOIN|linguaggio=SQL}}.
 
==== Equi-join ====
La ''equi-join'', noto come "l'unica operazione ammissibile", ha un particolare tipo di comparatore, detto ''theta join'', che utilizza come metodo di verifica, solamente l'uguaglianza matematica come regola di confronto. Usare altri operatori di confronto (come ad esempio {{Codice|codice=<|linguaggio=SQL}}) squalifica la ''join'' come ''equi-join''. La query riportata di seguito utilizza una ''equi-join'':
 
<syntaxhighlight lang="sql" line="1">
LA '''equi-join''', altrimenti conosciuta come '''equijoin''', ha un particolare tipo di comparatore, detto ''theta join'', che utilizza come metodo di verifica, solamente l'uguaglianza matematica come regola di confronto. Usando altri operatori di confronto (come ad esempio <code>&lt;</code>) squalifica la join come equi-join. La query riportata di seguito utilizza una equi-join:
<source lang=sql>
SELECT *
FROM Impiegati
INNER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
SQL fornisce una scorciatoia per definire le equi-joins, attraverso la keyword[[parola <code>riservata]] {{Codice|codice=USING</code>|linguaggio=SQL}}
 
<source lang=sql>
<syntaxhighlight lang="sql" line="1">
SELECT *
FROM Impiegati
INNER JOIN Dipartimenti
USING (ID_dipartimento)
</syntaxhighlight>
</source>
 
La ''keyword'' <code>{{Codice|codice=USING</code>|linguaggio=SQL}} è supportata da [[Microsoft SQL Server Management Studio]], [[MySQL]], [[Oracle Database|Oracle]], [[PostgreSQL]], [[SQLite]], ande [[IBM DB2|DB2/400]].
 
==== Natural join ====
Una {{Codice|codice=NATURAL JOIN|linguaggio=SQL}} offre ulteriori specializzazioni di ''equi-join''. Solitamente la {{Codice|codice=JOIN|linguaggio=SQL}} confronta colonne di tabelle diverse che hanno lo stesso nome. La {{Codice|codice=NATURAL JOIN|linguaggio=SQL}} fa proprio questo.
 
Nell'esempio che segue viene riportata la notazione {{Codice|codice=NATURAL JOIN|linguaggio=SQL}} equivalente alla prima {{Codice|codice=INNER JOIN|linguaggio=SQL}} definita:
Una [[natural join]] offre ulteriori specializzazioni di equi-joins. Solitamente la join confronta colonne di tabelle diverse che hanno lo stesso nome. La natural join fa proprio questo.
 
<syntaxhighlight lang="sql" line="1">
Nell'esempio che segue viene riportata la notazione natural join equivalente alla prima inner-join definita:
<source lang=sql>
SELECT *
FROM Impiegati
NATURAL JOIN Dipartimenti
</syntaxhighlight>
</source>
 
{| class="wikitable" style="text-align:center"
Riga 130 ⟶ 132:
|}
 
==== Cross join ====
[[File:SQL Join - 08 A Cross Join B.svg|miniatura|Immagine che rappresenta la {{Codice|codice=CROSS JOIN|linguaggio=SQL}} di due tabelle]]
Una {{Codice|codice=CROSS JOIN|linguaggio=SQL}}, ''cartesian join'' o ''product'' fornisce le basi (le infrastrutture informatiche) attraverso cui tutti i tipi di {{Codice|codice=INNER JOIN|linguaggio=SQL}} operano. Il risultato di una {{Codice|codice=CROSS JOIN|linguaggio=SQL}} è il [[prodotto cartesiano]] di tutte le righe delle tabelle che concorrono alla query di ''join''. È come dire che stiamo facendo una {{Codice|codice=INNER JOIN|linguaggio=SQL}} senza impostare la regola di confronto o in cui la regola di confronto ritorna sempre vero.
 
Date le due tabelle di partenza <math>A</math> e <math>B</math>, la cross join si scrive <math>A</math> × <math>B</math>.
Una '''[[cross join]]''', '''[[cartesian join]]''' or '''[[Product (mathematics)|product]]''' fornisce le basi (le infrastrutture informatiche) attraverso cui tutti i tipi di inner join operano. Il risultato di una cross join è il prodotto cartesiano di tutte le righe delle tabelle che concorrono alla query di join. È come dire che stiamo facendo una inner join senza impostare la regola di confronto o in cui la regola di confronto ritorna sempre vero.
 
Esempio di {{Codice|codice=CROSS JOIN|linguaggio=SQL}} esplicito:
Se A e B le tabelle di partenza, la cross join si scrive A × B.
 
<syntaxhighlight lang=sql>
Esempio di cross join esplicito:
<source lang=sql>
SELECT *
FROM Impiegati CROSS JOIN Dipartimenti
</syntaxhighlight>
</source>
 
Altro esempio implicito di cross{{Codice|codice=CROSS joinJOIN|linguaggio=SQL}}:
 
<source lang=sql>
<syntaxhighlight lang=sql>
SELECT *
FROM Impiegati, Dipartimenti;
</syntaxhighlight>
</source>
 
{| class="wikitable" style="text-align:center"
Riga 162 ⟶ 166:
| Santoro || 34 || Vendite || 31
|-
| Grassi || {{null resultCodice|codice=NULL|linguaggio=SQL}} || Vendite || 31
|-
| Rossi || 31 || Tecnico || 33
Riga 174 ⟶ 178:
| Santoro || 34 || Tecnico || 33
|-
| Grassi || {{null resultCodice|codice=NULL|linguaggio=SQL}} || Tecnico || 33
|-
| Rossi || 31 || Risorse umane || 34
Riga 186 ⟶ 190:
| Santoro || 34 || Risorse umane || 34
|-
| Grassi || {{null resultCodice|codice=NULL|linguaggio=SQL}} || Risorse umane || 34
|-
| Rossi || 31 || Promozione || 35
Riga 198 ⟶ 202:
| Santoro || 34 || Promozione || 35
|-
| Grassi || {{null resultCodice|codice=NULL|linguaggio=SQL}} || Promozione || 35
|}
 
== Outer joinsjoin ==
Una {{Codice|codice=OUTER JOIN|linguaggio=SQL}} non richiede che ci sia corrispondenza esatta tra le righe di due tabelle. La tabella risultante da una outer join trattiene tutti quei record che non hanno alcuna corrispondenza tra le tabelle. Le {{Codice|codice=OUTER JOIN|linguaggio=SQL}} si suddividono in {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}}, {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}}, e {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}}, in base a quale sia la tabella di cui intendiamo trattenere i valori in caso di mancata corrispondenza della regola di confronto da (sinistra, destra, o entrambi). In questo caso ''left'' (sinistra) e ''right'' (destra) si riferiscono ai due lati della ''keyword'' {{Codice|codice=JOIN|linguaggio=SQL}}.
 
=== Nota sulle clausole WHERE e ON ===
Una [[outer join]] non richiede che ci sia corrispondenza esatta tra le righe di due tabelle. La tabella risultante da una outer join trattiene tutti quei record che non hanno alcuna corrispondenza tra le tabelle. Le outer joins si suddividono in left outer joins, right outer joins, e full outer joins, in base a quale sia la tabella di cui intendiamo trattenere i valori in caso di mancata corrispondenza della regola di confronto da (sinistra, destra, o entrambi).
Si sottolinea come esista un ordine di esecuzione tra le condizioni specificate nella {{Codice|codice=WHERE|linguaggio=SQL}} e quelle presenti nella {{Codice|codice=ON|linguaggio=SQL}}.
 
Specificatamente le clausole presenti nella {{Codice|codice=ON|linguaggio=SQL}} sono valutate anteriormente all'esecuzione della {{Codice|codice=JOIN|linguaggio=SQL}} mentre le clausole nella where sono valutate successivamente all'esecuzione della {{Codice|codice=JOIN|linguaggio=SQL}}.
(In questo caso ''left'' (sinistra) e ''right'' (destra) si riferiscono ai due lati della keyword <code>JOIN</code>.)
 
=== Left outer join ===
[[File:SQL Join - 01b A Left Join B.svg|miniatura|[[Diagramma di Venn]] che rappresenta la {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}} di due tabelle]]
 
Il risultato di una query ''left{{Codice|codice=LEFT outerOUTER join''JOIN|linguaggio=SQL}} (o semplicemente '''left{{Codice|codice=LEFT join'''JOIN|linguaggio=SQL}}) per le tabelle <math>A</math> e <math>B</math> contiene sempre tutti i record della tabella di sinistra ("''left"'') <math>A</math>, mentre vengono estratti dalla tabella di destra ("''right"'') <math>B</math> solamente le righe che trovano corrispondenza nella regola di confronto della join. Questo significa che se la clausola <code>{{Codice|codice=ON</code>|linguaggio=SQL}} trova 0 (zero) righe in <math>B</math>, la join{{Codice|codice=JOIN|linguaggio=SQL}} mostrerà una riga risultante con valore {{Codice|codice=NULL|linguaggio=SQL}} in tutte le colonne corrispondenti al risultato per lale colonnacolonne di <math>B</math>.
 
Esempio di una left outer join:
 
<sourcesyntaxhighlight lang="sql" line="1">
SELECT *
FROM Impiegati LEFT OUTER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
{| class="wikitable" style="text-align:center"
Riga 230 ⟶ 236:
| Monti || 34 || Risorse umane || 34
|-
| ''Grassi'' || {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}}
|-
| Mancini || 33 || Tecnico || 33
|}
 
=== Right outer joinsjoin ===
[[File:SQL Join - 03b A Right Join B.svg|miniatura|[[Diagramma di Venn]] che rappresenta la {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}} di due tabelle]]
Una {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}} (o {{Codice|codice=RIGHT JOIN|linguaggio=SQL}}) semplicemente ricalca il funzionamento della {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}}, ma invertendo l'ordine delle tabelle interessate.
 
Il risultato di una query {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}} per le tabelle <math>A</math> e <math>B</math> contiene sempre tutti i record della tabella di destra (''right'') <math>B</math>, mentre vengono estratti dalla tabella di sinistra (''left'') <math>A</math> solamente le righe che trovano corrispondenza nella regola di confronto della {{Codice|codice=JOIN|linguaggio=SQL}}. Questo significa che se la clausola {{Codice|codice=ON|linguaggio=SQL}} trova zero righe in <math>A</math>, la {{Codice|codice=JOIN|linguaggio=SQL}} mostrerà una riga risultante con valore {{Codice|codice=NULL|linguaggio=SQL}} in tutte le colonne corrispondenti al risultato per le colonne di <math>A</math>.
Una '''[[right outer join]]''' (o '''[[right join]]''') semplicemente ricalca il funzionamento della left outer join, ma invertendo l'ordine delle tabelle interessate. Every row from the "right" table (B) will appear in the joined table at least once. If no matching row from the "left" table (A) exists, NULL will appear in columns from A for those records that have no match in A.
 
Esempio di una {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}}:
A right outer join returns all the values from the right table and matched values from the left table (NULL in case of no matching join predicate).
 
<syntaxhighlight lang="sql" line="1">
For example, this allows us to find each Impiegati and his or her Dipartimenti, but still show Dipartimentis that have no Impiegatis.
 
Example right outer join, with the additional result row italicized:
 
<source lang=sql>
SELECT *
FROM Impiegati RIGHT OUTER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
{| class="wikitable" style="text-align:center"
! Impiegati.Cognome !! Impiegati.ID_dipartimento !! Dipartimenti.Nome_dipartimento !! Dipartimenti.ID_dipartimento
|-
| Monti || 34 || Risorse umane || 34
Riga 264 ⟶ 268:
| Rossi || 31 || Vendite || 31
|-
| {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}} || ''Promozione'' || ''35''
|}
 
In pratica sono utilizzate maggiormente le query di {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}} rispetto a quelle di {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}}, ma possono verificarsi rari casi in cui in query molto complesse ci sia la necessità di utilizzare contemporaneamente il criterio di {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}} e di {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}}.
In practice, explicit right outer joins are rarely used, since they can always be replaced with left outer joins (with the table order switched) and provide no additional functionality. The result above is produced also with a left outer join:
 
Lo stesso risultato della precedente {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}} si può ripetere usando il tipo {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}}:
<source lang=sql>
 
<syntaxhighlight lang="sql" line="1">
SELECT *
FROM Dipartimenti LEFT OUTER JOIN Impiegati
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
=== Full outer join ===
[[File:SQL Join - 05b A Full Join B.svg|miniatura|[[Diagramma di Venn]] che rappresenta la {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}} di due tabelle]]
Una {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}} combina i risultati delle due tabelle <math>A</math> e <math>B</math> tenendo conto di tutte le righe delle tabelle, anche di quelle che non hanno corrispondenza tra di loro.
 
Il risultato di una query {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}} per le tabelle <math>A</math> e <math>B</math> contiene sempre tutti i record della tabella di sinistra (''left'') <math>A</math>, estraendo dalla tabella di destra (''right'') <math>B</math> solamente le righe che trovano corrispondenza nella regola di confronto della join; inoltre verranno estratti tutti i record della tabella di sinistra (''left'') <math>A</math> che non trovano corrispondenza nella tabella di destra (''right'') <math>B</math> impostando a {{Codice|codice=NULL|linguaggio=SQL}} i valori di tutte le colonne della tabella <math>B</math> e tutti i record della tabella di destra (''right'') <math>B</math> che non trovano corrispondenza nella tabella di sinistra (''left'') <math>A</math> impostando a {{Codice|codice=NULL|linguaggio=SQL}} i valori di tutte le colonne della tabella <math>A</math>.
A '''[[full outer join]]''' combines the results of both left and right outer joins. The joined table will contain all records from both tables, and fill in NULLs for missing matches on either side.
 
For example, this allows us to see each Impiegati who is in a Dipartimenti and each Dipartimenti that has an Impiegati, but also see each Impiegati who is not part of a Dipartimenti and each Dipartimenti which doesn't have an Impiegati.
 
Esempio di una {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}}:
Example full outer join:
 
<sourcesyntaxhighlight lang="sql" line="1">
SELECT *
FROM Impiegati
FULL OUTER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</syntaxhighlight>
</source>
 
{| class="wikitable" style="text-align:center"
Riga 299 ⟶ 305:
| Santoro || 34 || Risorse umane || 34
|-
| ''Grassi'' || {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}}
|-
| Mancini || 33 || Tecnico || 33
Riga 305 ⟶ 311:
| Rossi || 31 || Vendite || 31
|-
| {{null resultCodice|codice=NULL|linguaggio=SQL}} || {{null resultCodice|codice=NULL|linguaggio=SQL}} || ''Promozione'' || ''35''
|}
 
Alcuni database (come per esempio MySQL) non supportano direttamente questa funzionalità, ma la si può emulare attraverso la combinazione di {{Codice|codice=LEFT OUTER JOIN|linguaggio=SQL}} e {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}} per mezzo della parola riservata {{Codice|codice=UNION|linguaggio=SQL}}.
Some database systems (like MySQL) do not support this functionality directly, but they can emulate it through the use of left and right outer joins and [[Union (SQL)|union]]s. The same example can appear as follows:
 
<source lang=sql>
La creazione di una query di {{Codice|codice=FULL OUTER JOIN|linguaggio=SQL}} si realizzerà come segue:
 
<syntaxhighlight lang="sql" line="1">
SELECT *
FROM Impiegati
Riga 320 ⟶ 329:
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
WHERE Impiegati.ID_dipartimento IS NULL
</syntaxhighlight>
</source>
 
Allo stesso modo senza utilizzare nemmeno la query di {{Codice|codice=RIGHT OUTER JOIN|linguaggio=SQL}}:
SQLite does not support right join, so outer join can be emulated as follows:
 
<sourcesyntaxhighlight lang="sql" line="1">
SELECT Impiegati.*, Dipartimenti.*
FROM Impiegati
Riga 335 ⟶ 344:
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
WHERE Impiegati.ID_dipartimento IS NULL
</syntaxhighlight>
</source>
 
== Self-join ==
La ''self-join'' serve a unire una tabella con se stessa.
 
== Voci correlate ==
A self-join is joining a table to itself.<ref>{{Harvnb|Shah|2005|p=165}}</ref> This is best illustrated by the following example.
* [[Sort merge join]]
 
=== Example ===
 
A query to find all pairings of two Impiegatis in the same country is desired. If you had two separate tables for Impiegatis and a query which requested Impiegatis in the first table having the same country as Impiegatis in the second table, you could use a normal join operation to find the answer table. However, all the Impiegati information is contained within a single large table. <ref> Adapted from {{harvnb|Pratt|2005|pp=115&ndash;6}}</ref>
 
Considering a modified <code>Impiegati</code> table such as the following:
{| class="wikitable" style="text-align:center; float:left; margin-right:5px"
|+Impiegati Table
|-
! ImpiegatiID !! Cognome !! Country !! ID_dipartimento
|-
| 123 || Rossi || Australia || 31
|-
| 124 || Bianchi || Australia || 33
|-
| 145 || Mancini || Australia || 33
|-
| 201 || Santoro || United States || 34
|-
| 305 || Monti || United Kingdom || 34
|-
| 306 || Grassi || United Kingdom || {{null result}}
|}
<br clear="all" />
 
An example solution query could be as follows:
 
<source lang=sql>
SELECT F.ImpiegatiID, F.Cognome , S.ImpiegatiID, S.Cognome , F.Country
FROM Impiegati F, Impiegati S
WHERE F.Country = S.Country
AND F.ImpiegatiID < S.ImpiegatiID
ORDER BY F.ImpiegatiID, S.ImpiegatiID;
</source>
 
Which results in the following table being generated.
{| class="wikitable" style="text-align:center; float:left; margin-right:5px"
|+Impiegati Table after Self-join by Country
|-
! ImpiegatiID !! Cognome !! ImpiegatiID !! Cognome !! Country
|-
| 123 || Rossi || 124 || Bianchi || Australia
|-
| 123 || Rossi || 145 || Mancini || Australia
|-
| 124 || Bianchi || 145 || Mancini || Australia
|-
| 305 || Monti || 306 || Grassi || United Kingdom
|}
<br clear="all" />
For this example, note that:
*<code>F</code> and <code>S</code> are [[alias (SQL)|aliases]] for the first and second copies of the Impiegati table.
*The condition <code>F.Country = S.Country</code> excludes pairings between Impiegatis in different countries. The example question only wanted pairs of Impiegatis in the same country.
*The condition <code>F.ImpiegatiID < S.ImpiegatiID</code> excludes pairings where the <code>ImpiegatiID</code>s are the same.
*<code>F.ImpiegatiID < S.ImpiegatiID</code> also excludes duplicate pairings. Without it only the following less useful part of the table would be generated (for the United Kingdom only shown):
{| class="wikitable" style="text-align:center; float:left; margin-right:5px"
! ImpiegatiID !! Cognome !! ImpiegatiID !! Cognome !! Country
|-
| 305 || Monti || 305 || Monti || United Kingdom
|-
| 305 || Monti || 306 || Grassi || United Kingdom
|-
| 306 || Grassi || 305 || Monti || United Kingdom
|-
| 306 || Grassi || 306 || Grassi || United Kingdom
|}
<br clear="all" />
Only one of the two middle pairings is needed to satisfy the original question, and the topmost and bottommost are of no interest at all in this example.
 
== Alternatives ==
 
The effect of outer joins can also be obtained using [[correlated subquery|correlated subqueries]]. For example
 
<source lang=sql>
SELECT Impiegati.Cognome , Impiegati.ID_dipartimento, Dipartimenti.Nome_dipartimento
FROM Impiegati LEFT OUTER JOIN Dipartimenti
ON Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento
</source>
 
can also be written as
 
<source lang=sql>
SELECT Impiegati.Cognome , Impiegati.ID_dipartimento,
(SELECT Dipartimenti.Nome_dipartimento
FROM Dipartimenti
WHERE Impiegati.ID_dipartimento = Dipartimenti.ID_dipartimento )
FROM Impiegati
</source>
 
== Implementation ==
 
Much work in database-systems has aimed at efficient implementation of joins, because relational systems commonly call for joins, yet face difficulties in optimising their efficient execution. The problem arises because (inner) joins operate both [[commutative]]ly and [[associative]]ly. In practice, this means that the user merely supplies the list of tables for joining and the join conditions to use, and the database system has the task of determining the most efficient way to perform the operation. A [[query optimizer]] determines how to execute a query containing joins. A query optimizer has two basic freedoms:
 
# '''Join order''': Because joins function commutatively and associatively, the order in which the system joins tables does not change the final result-set of the query. However, join-order '''does''' have an enormous impact on the cost of the join operation, so choosing the best join order becomes very important.
# '''Join method''': Given two tables and a join condition, multiple [[algorithm]]s can produce the result-set of the join. Which algorithm runs most efficiently depends on the sizes of the input tables, the number of rows from each table that match the join condition, and the operations required by the rest of the query.
 
Many join-algorithms treat their inputs differently. One can refer to the inputs to a join as the "outer" and "inner" join operands, or "left" and "right", respectively. In the case of nested loops, for example, the database system will scan the entire inner [[table (database)|relation]] for each row of the outer relation.
 
One can classify query-plans involving joins as follows:<ref name=Yu1998>{{Harvnb|Yu|Meng|1998|p=213}}
</ref>
 
; left-deep : using a base table (rather than another join) as the inner operand of each join in the plan
; right-deep : using a base table as the outer operand of each join in the plan
; bushy : neither left-deep nor right-deep; both inputs to a join may themselves result from joins
 
These names derive from the appearance of the [[query plan]] if drawn as a [[Tree data structure|tree]], with the outer join relation on the left and the inner relation on the right (as convention dictates).
 
=== Join algorithms ===
 
Three fundamental algorithms exist for performing a join operation.
 
==== Nested loops ====
 
{{main2|Nested loop join|block nested loop}}
 
Use of nested loops produces the simplest join-algorithm. For each [[tuple]] in the outer join relation, the system scans the entire inner-join relation and appends any tuples that match the join-condition to the result set. Naturally, this algorithm performs poorly with large join-relations: inner or outer or both. An [[index (database)|index]] on columns in the inner relation in the join-predicate can enhance performance.
 
The block nested loops (BNL) approach offers a refinement to this technique: for every block in the outer relation, the system scans the entire inner relation. For each match between the current inner tuple and one of the tuples in the current block of the outer relation, the system adds a tuple to the join result-set. This variant means doing more computation for each tuple of the inner relation, but far fewer scans of the inner relation.
 
==== '''Merge join'''====
 
If both join relations come in order, sorted by the join attribute(s), the system can perform the join trivially, thus:
 
:# Consider the current "group" of tuples from the inner relation; a group consists of a set of contiguous tuples in the inner relation with the same value in the join attribute.
:# For each matching tuple in the current inner group, add a tuple to the join result. Once the inner group has been exhausted, advance both the inner and outer scans to the next group.
 
Merge joins offer one reason why many optimizers keep track of the sort order produced by query plan operators—if one or both input relations to a merge join arrives already sorted on the join attribute, the system need not perform an additional sort. Otherwise, the DBMS will need to perform the sort, usually using an [[external sort]] to avoid consuming too much memory.
 
{{seealso|Sort-Merge Join}}
 
==== Hash join ====
 
{{main|Hash join}}
 
A hash join algorithm can only produce equi-joins. The database system pre-forms access to the tables concerned by building [[hash table]]s on the join-attributes. The lookup in hash tables operates much faster than through index trees. However, one can compare hashed values only for equality, not for other relationships.
 
== See also ==
 
* [[SQL]]
* [[Query optimizer]]
* [[Composition of relations]]
 
== Notes ==
{{reflist|2}}
 
== References ==
 
== Altri progetti ==
*{{citation
{{interprogetto|preposizione=sulla}}
|last= Pratt
|first= Phillip J
|title= A Guide To SQL, Seventh Edition
|publisher= Thomson Course Technology
|year= 2005
|isbn= 9780619216740
}}
*{{citation
|last=Shah
|first= Nilesh
|title= Database Systems Using Oracle - A Simplified Guide to SQL and PL/SQL Second Edition
|edition= International Edition
|publisher= Pearson Education International
|origyear= 2002
|year= 2005
|isbn= 0131911805
}}
*{{citation
|url= http://books.google.com/books?id=aBHRDhrrehYC
|accessdate= 2009-03-03
|title= Principles of Database Query Processing for Advanced Applications
|last = Yu
|first= Clement T.
|last2= Meng
|first2= Weiyi
|year= 1998
|publisher= Morgan Kaufmann
|isbn= 9781558604346
}}
 
== ExternalCollegamenti linksesterni ==
* {{FOLDOC||join}}
* [http://blog.sqlauthority.com/2009/04/13/sql-server-introduction-to-joins-basic-of-joins/ SQL SERVER - Introduction to JOINs - Basic of JOINs]
* {{Cita web | url = https://kb.askmonty.org/it/introduzione-alle-join/ | titolo = Introduzione alle JOIN (nella knowledgebase di AskMonty) | accesso = 18 ottobre 2022 | urlarchivio = https://archive.is/20121220173307/https://kb.askmonty.org/it/introduzione-alle-join/ | dataarchivio = 20 dicembre 2012 }}
* [http://www.sqldatabasetutorial.com/sqltutorial/sqljoin-innerjoin.aspx SQL Inner Join with visual explanation]
* [http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sqlug/html/sqlug/sqlug138.htm Sybase ASE 15 Joins]
* [http://dev.mysql.com/doc/refman/5.0/en/join.html MySQL 5.0 Joins]
* [http://www.oraclepassport.com/OracleJoins.html Oracle Joins - Quick Reference]
* [http://www.postgresqlguide.com/retrieving-data-from-multiple-tables-by-using-sql-join.aspx PostgreSQL Join with Query Explain]
* [http://www.postgresql.org/docs/8.3/static/tutorial-join.html PostgreSQL 8.3 Joins]
* [http://msdn2.microsoft.com/en-us/library/ms191517.aspx Joins in Microsoft SQL Server]
* [http://maxdb.sap.com/currentdoc/45/f31c38e95511d5995d00508b5d5211/content.htm Joins in MaxDB 7.6]
* [http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/queries006.htm Joins in Oracle 11g]
* [http://www.partow.net/programming/databasealgos/index.html Various join-algorithm implementations]
* [http://www.codinghorror.com/blog/archives/000976.html A Visual Explanation of SQL Joins]
* [http://www.halfgaar.net/sql-joins-are-easy Another visual explanation of SQL joins, along with some set theory]
* [http://www.gplivna.eu/papers/sql_join_types.htm SQL join types classified with examples]
* [http://weblogs.sqlteam.com/jeffs/archive/2007/04/19/Full-Outer-Joins.aspx An alternative strategy to using FULL OUTER JOIN]
{{databases}}
 
{{Principali linguaggi di programmazione}}
[[Category:SQL keywords]]
{{portale|informatica}}
[[Category:Articles with example SQL code]]
 
[[csCategoria:JOINSQL]]
[[es:Join]]
[[fr:Jointure (informatique)]]
[[no:Join (SQL)]]
[[ru:Алгоритм соединения (СУБД)]]
[[uk:Об'єднання (SQL)]]
[[vi:Join (SQL)]]