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 *FROM employee INNER JOIN department USING (DepartmentID);
Il costrutto USING
è più di un semplice zucchero sintattico, tuttavia, poiché il set di risultati è diverso dal risultato insieme della versione con il predicato esplicito. In particolare, tutte le colonne menzionate nell’elenco USING
verranno visualizzate una sola volta, con un nome non qualificato, anziché una per ciascuna tabella nel join. Nel caso precedente, sarà presente una sola DepartmentID
colonna e nessuna employee.DepartmentID
o department.DepartmentID
.
La clausola USING
non è supportata da MS SQL Server e Sybase.
Natural joinEdit
Il naturale join è un caso speciale di equi-join. Natural join (⋈) è un operatore binario scritto come (R ⋈ S) dove R e S sono relazioni. Il risultato del join naturale è l’insieme di tutte le combinazioni di tuple in R e S che sono uguali nei loro nomi di attributi comuni.Per un esempio, considera le tabelle Employee e Dept e la loro unione naturale:
|
|
|
Può essere utilizzato anche per definire la composizione delle relazioni. Ad esempio, la composizione di Employee e Dept è la loro unione come mostrato sopra, proiettata su tutti tranne l’attributo comune DeptName. Nella teoria delle categorie, l’unione è precisamente il prodotto in fibra.
L’unione naturale è probabilmente uno degli operatori più importanti poiché è la controparte relazionale di AND logico. Si noti che se la stessa variabile appare in ciascuno dei due predicati collegati da AND, allora quella variabile rappresenta la stessa cosa ed entrambi gli aspetti devono sempre essere sostituiti dallo stesso valore. In particolare, il join naturale consente la combinazione di relazioni associate da una chiave esterna. Ad esempio, nell’esempio precedente una chiave esterna probabilmente contiene da Employee.DeptName a Dept.DeptName e quindi l’unione naturale di Employee e Dept combina tutti i dipendenti con i loro reparti. Questo funziona perché la chiave esterna è valida tra attributi con lo stesso nome. Se questo non è il caso, ad esempio nella chiave esterna da Dept.manager a Employee.Name, queste colonne devono essere rinominate prima che venga eseguito il join naturale. Tale join è talvolta indicato anche come equi-join.
Più formalmente la semantica del join naturale è definita come segue:
R ⋈ S = {t ∪ s ∣ t ∈ R ∧ s ∈ S ∧ F un (t ∪ s)} {\ displaystyle R \ bowtie S = \ left \ {t \ cup s \ mid t \ in R \ \ land \ s \ in S \ \ land \ {\ mathit {Fun}} (t \ cup s) \ right \}},
dove Fun è un predicato vero per una relazione r se e solo se r è una funzione. Di solito è richiesto che R e S debbano avere almeno un attributo comune, ma se questo vincolo viene omesso e R e S non hanno attributi comuni, l’unione naturale diventa esattamente il prodotto cartesiano.
il join naturale può essere simulato con le primitive di Codd come segue. Siano c1,…, cm i nomi degli attributi comuni a R e S, r1,…, rn i nomi degli attributi univoci di R e siano s1,…, sk il attributi unici di S. Inoltre, si supponga che i nomi degli attributi x1,…, xm non siano né in R né in S. In un primo passaggio i nomi degli attributi comuni in S possono ora essere rinominati:
T = ρ x 1 / c 1,…, xm / cm (S) = ρ x 1 / c 1 (ρ x 2 / c 2 (… ρ xm / cm (S)…)) {\ displaystyle T = \ rho _ {x_ {1} / c_ {1}, \ ldots, x_ {m} / c_ {m}} (S) = \ rho _ {x_ {1} / c_ {1}} (\ rho _ {x_ {2} / c_ {2 }} (\ ldots \ rho _ {x_ {m} / c_ {m}} (S) \ ldots))}
Quindi prendiamo il prodotto cartesiano e selezioniamo le tuple che devono essere unite:
U = π r 1,…, rn, c 1,…, cm, s 1,…, sk (P) {\ displaystyle U = \ pi _ {r_ {1}, \ ldots, r_ {n}, c_ {1}, \ ldots, c_ {m}, s_ {1}, \ ldots, s_ {k}} (P)}
Un join naturale è un tipo di equi- join dove il predicato di join sorge implicitamente confrontando tutte le colonne in entrambe le tabelle che hanno gli stessi nomi di colonna nelle tabelle unite. La tabella unita risultante contiene solo una colonna per ogni coppia di colonne con lo stesso nome. Nel caso in cui non vengano trovate colonne con lo stesso nome, il risultato è un cross join.
La maggior parte degli esperti concorda sul fatto che i NATURAL JOIN sono pericolosi e quindi ne sconsigliano fortemente l’uso. Il pericolo deriva dall’aggiunta inavvertitamente di una nuova colonna, denominata come un’altra colonna nell’altra tabella. Un join naturale esistente potrebbe quindi utilizzare “naturalmente” la nuova colonna per i confronti, effettuando confronti / corrispondenze utilizzando criteri diversi (da colonne diverse) rispetto a prima. Pertanto una query esistente potrebbe produrre risultati diversi, anche se i dati nelle tabelle non sono stati modificati, ma solo aumentati.L’utilizzo dei nomi di colonna per determinare automaticamente i collegamenti alle tabelle non è un’opzione nei database di grandi dimensioni con centinaia o migliaia di tabelle in cui imporrebbe un vincolo irrealistico alle convenzioni di denominazione. I database del mondo reale sono comunemente progettati con dati di chiavi esterne che non vengono popolati in modo coerente (sono consentiti valori NULL), a causa delle regole e del contesto aziendali. È pratica comune modificare i nomi delle colonne di dati simili in tabelle diverse e questa mancanza di rigida coerenza relega i join naturali a un concetto teorico per la discussione.
La query di esempio sopra per i join interni può essere espressa come un naturale partecipare nel modo seguente:
SELECT *FROM employee NATURAL JOIN department;
Come con la clausola USING
esplicita, solo una colonna DepartmentID si trova nella tabella unita, senza qualificatore:
DepartmentID | Employee.LastName | Department.DepartmentName |
---|---|---|
34 | Smith | Clericale |
33 | Jones | Ingegneria |
34 | Robinson | Ufficio |
33 | Heisenberg | Ingegneria |
31 | Rafferty | Vendite |
PostgreSQL, MySQL e Oracle su pport natural joins; Microsoft T-SQL e IBM DB2 non lo fanno. Le colonne utilizzate nel join sono implicite, quindi il codice di join non mostra le colonne previste e una modifica nei nomi delle colonne potrebbe modificare i risultati. Nello standard SQL: 2011, i join naturali fanno parte del pacchetto opzionale F401, “Extended join table”.
In molti ambienti di database i nomi delle colonne sono controllati da un fornitore esterno, non dallo sviluppatore della query. Un join naturale presuppone stabilità e coerenza nei nomi delle colonne che possono cambiare durante gli aggiornamenti della versione richiesti dal fornitore.