Un inner join richiede che ogni riga nelle due tabelle unite abbia valori di colonna corrispondenti ed è un’operazione di join comunemente usata nelle applicazioni ma non dovrebbe essere considerata la scelta migliore in tutte le situazioni. Inner join crea una nuova tabella dei risultati combinando i valori di colonna di due tabelle (A e B) in base al predicato di join. La query confronta ogni riga di A con ogni riga di B per trovare tutte le coppie di righe che soddisfano il predicato di join. Quando il predicato di join è soddisfatto dalla corrispondenza di valori non NULL, i valori di colonna per ciascuna coppia di righe di A e B corrispondenti vengono combinati in una riga di risultato.
Il risultato del join può essere definito come risultato di prendere prima il prodotto cartesiano (o Cross join) di tutte le righe nelle tabelle (combinando ogni riga nella tabella A con ogni riga nella tabella B) e quindi restituire tutte le righe che soddisfano il predicato di join. Le implementazioni SQL effettive normalmente utilizzano altri approcci, come hash join o sort-merge join, poiché il calcolo del prodotto cartesiano è più lento e spesso richiederebbe una quantità di memoria eccessivamente grande da memorizzare.
SQL specifica due differenti sintattiche modi per esprimere i join: la “notazione di join esplicita” e la “notazione di join implicita”. La “notazione di join implicita” non è più considerata una best practice, sebbene i sistemi di database la supportino ancora.
La “notazione di join esplicita” utilizza la parola chiave JOIN
, facoltativamente preceduto dalla parola chiave INNER
, per specificare la tabella a cui unirsi, e dalla parola chiave ON
per specificare i predicati per il join, come in il seguente esempio:
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName FROM employee INNER JOIN department ONemployee.DepartmentID = department.DepartmentID;
Employee.LastName |
Employee.DepartmentID |
Department.DepartmentName |
Robinson |
34 |
Ufficio |
Jones |
33 |
Ingegneria |
Smith |
34 |
Ufficio |
Heisenberg |
33 |
Ingegneria |
Rafferty |
31 |
Vendite |
La “notazione di join implicita” elenca semplicemente t egli tabelle per unirsi, nella clausola FROM
dell’istruzione SELECT
, utilizzando virgole per separarle. Quindi specifica un cross join e la clausola WHERE
può applicare predicati di filtro aggiuntivi (che funzionano in modo comparabile ai predicati di join nella notazione esplicita).
L’esempio seguente è equivalente al precedente, ma questa volta utilizza la notazione di join implicita:
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName FROM employee, departmentWHERE employee.DepartmentID = department.DepartmentID;
Le query fornite negli esempi sopra si unirà alle tabelle Employee e Department utilizzando la colonna DepartmentID di entrambe le tabelle. Quando il DepartmentID di queste tabelle corrisponde (ovvero il predicato di join è soddisfatto), la query combinerà le colonne LastName, DepartmentID e DepartmentName delle due tabelle in una riga di risultati. Se DepartmentID non corrisponde, non viene generata alcuna riga di risultati.
Pertanto il risultato dell’esecuzione della query precedente sarà:
Employee.LastName |
Employee.DepartmentID |
Department.DepartmentName |
Robinson |
34 |
Clericale |
Jones |
33 |
Ingegneria |
Smith |
34 |
Ufficio |
Heisenberg |
33 |
Ingegneria |
Rafferty |
31 |
Vendite |
Il dipendente “Williams” e il dipartimento “Marketing” non vengono visualizzati nei risultati dell’esecuzione della query. Nessuno di questi ha righe corrispondenti nell’altra rispettiva tabella: “Williams” non ha un reparto associato e nessun dipendente ha l’ID reparto 35 (“Marketing”). A seconda dei risultati desiderati, questo comportamento può essere un bug sottile, che può essere evitato sostituendo il join interno con un join esterno.
Inner join e valori NULL Modifica
I programmatori dovrebbero prendere attenzione particolare quando si uniscono tabelle su colonne che possono contenere valori NULL, poiché NULL non corrisponderà mai a nessun altro valore (nemmeno NULL stesso), a meno che la condizione di join non utilizzi esplicitamente un predicato di combinazione che verifica prima che le colonne di join siano NOT NULL
prima di applicare le restanti condizioni del predicato. L’Inner Join può essere utilizzato in sicurezza solo in un database che impone l’integrità referenziale o in cui è garantito che le colonne di join non siano NULL. Molti database relazionali di elaborazione delle transazioni si basano sugli standard di aggiornamento dei dati di atomicità, coerenza, isolamento, durabilità (ACID) per garantire l’integrità dei dati, rendendo gli inner join una scelta appropriata. Tuttavia, i database delle transazioni di solito hanno anche colonne di join desiderabili che possono essere NULL.Molti database relazionali di reporting e data warehouse utilizzano aggiornamenti batch ETL (Extract, Transform, Load) ad alto volume che rendono l’integrità referenziale difficile o impossibile da applicare, risultando in colonne di join potenzialmente NULL che un autore di query SQL non può modificare e che causano l’omissione di join interni dati senza indicazione di errore. La scelta di utilizzare un inner join dipende dalla progettazione del database e dalle caratteristiche dei dati. Un join esterno sinistro può solitamente essere sostituito con un join interno quando le colonne di join in una tabella possono contenere valori NULL.
Qualsiasi colonna di dati che può essere NULL (vuota) non dovrebbe mai essere usata come collegamento in un join interno, a meno che il risultato desiderato non sia eliminare le righe con il valore NULL. Se le colonne di join NULL devono essere rimosse deliberatamente dal set di risultati, un join interno può essere più veloce di un join esterno perché il join e il filtro della tabella vengono eseguiti in un unico passaggio. Al contrario, un inner join può comportare prestazioni estremamente lente o addirittura un arresto anomalo del server se utilizzato in una query di grandi volumi in combinazione con le funzioni del database in una clausola SQL Where. Una funzione in una clausola SQL Where può far sì che il database ignori gli indici di tabella relativamente compatti. Il database può leggere e unire le colonne selezionate da entrambe le tabelle prima di ridurre il numero di righe utilizzando il filtro che dipende da un valore calcolato, determinando una quantità relativamente enorme di elaborazione inefficiente.
Quando un risultato è impostato viene prodotto unendo più tabelle, comprese le tabelle principali utilizzate per cercare descrizioni di testo completo di codici identificativi numerici (una tabella di ricerca), un valore NULL in una qualsiasi delle chiavi esterne può comportare l’eliminazione dell’intera riga dal set di risultati, senza indicazione di errore. Una query SQL complessa che include uno o più inner join e diversi outer join presenta lo stesso rischio di valori NULL nelle colonne dei link di inner join.
Un impegno per il codice SQL contenente inner join presuppone che le colonne di join NULL non lo faranno essere introdotto da modifiche future, inclusi aggiornamenti del fornitore, modifiche di progettazione ed elaborazione di massa al di fuori delle regole di convalida dei dati dell’applicazione, come conversioni di dati, migrazioni, importazioni di massa e unioni.
È possibile classificare ulteriormente gli inner join come equi-join, come natural join o cross-join.
Equi-joinEdit
Un equi-join è un tipo specifico di join basato sul confronto, che utilizza solo confronti di uguaglianza nel predicato di join. L’utilizzo di altri operatori di confronto (come <
) squalifica un join come equi-join. La query mostrata sopra ha già fornito un esempio di equi-join:
SELECT *FROM employee JOIN department ON employee.DepartmentID = department.DepartmentID;
Possiamo scrivere equi-join come di seguito,
SELECT *FROM employee, departmentWHERE employee.DepartmentID = department.DepartmentID;
Se co le colonne in un equi-join hanno lo stesso nome, SQL-92 fornisce una notazione abbreviata opzionale per esprimere equi-join, tramite il costrutto USING
:
SELECT
read more