Join (SQL)
Een inner join vereist dat elke rij in de twee samengevoegde tabellen overeenkomende kolomwaarden heeft, en is een veelgebruikte join-bewerking in applicaties, maar mag niet als de beste keuze worden beschouwd in alle situaties. Inner join maakt een nieuwe resultatentabel door kolomwaarden van twee tabellen (A en B) te combineren op basis van het join-predikaat. De query vergelijkt elke rij A met elke rij B om alle paren rijen te vinden die voldoen aan het samenvoegpredikaat. Wanneer aan het joinpredicaat is voldaan door niet-NULL-waarden te matchen, worden kolomwaarden voor elk paar rijen A en B gecombineerd tot een resultaatrij.
Het resultaat van de join kan worden gedefinieerd als de uitkomst van eerst het Cartesiaans product (of Cross join) van alle rijen in de tabellen nemen (elke rij in tabel A combineren met elke rij in tabel B) en vervolgens alle rijen retourneren die voldoen aan het joinpredikaat. Werkelijke SQL-implementaties gebruiken normaal gesproken andere benaderingen, zoals hash-joins of sort-merge joins, aangezien het berekenen van het Cartesiaanse product langzamer is en vaak een onbetaalbaar grote hoeveelheid geheugen vereist om op te slaan.
SQL specificeert twee verschillende syntactische manieren om joins uit te drukken: de “expliciete join-notatie” en de “impliciete join-notatie”. De “impliciete samenvoegingsnotatie” wordt niet langer als een best practice beschouwd, hoewel databasesystemen dit nog steeds ondersteunen.
De “expliciete samenvoegingsnotatie” gebruikt het JOIN
sleutelwoord, optioneel voorafgegaan door het INNER
sleutelwoord, om de tabel te specificeren om mee te doen, en het ON
sleutelwoord om de predikaten voor de join te specificeren, zoals in het volgende voorbeeld:
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName FROM employee INNER JOIN department ONemployee.DepartmentID = department.DepartmentID;
Werknemer.Lastnaam | Werknemer.DepartmentID | Afdeling.Departmentnaam |
---|---|---|
Robinson | 34 | Administratief |
Jones | 33 | Techniek |
Smith | 34 | Administratief |
Heisenberg | 33 | Engineering |
Rafferty | 31 | Verkoop |
De “impliciete join-notatie” geeft gewoon t e tabellen om mee te doen, in de FROM
clausule van de SELECT
instructie, met komma’s om ze te scheiden. Het specificeert dus een cross-join, en de WHERE
-clausule kan aanvullende filterpredikaten toepassen (die vergelijkbaar werken met de join-predicaten in de expliciete notatie).
Het volgende voorbeeld is gelijk aan het vorige, maar nu met de impliciete samenvoegingsnotatie:
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName FROM employee, departmentWHERE employee.DepartmentID = department.DepartmentID;
De vragen die in de voorbeelden worden gegeven hierboven worden de tabellen Werknemer en Afdeling samengevoegd met behulp van de kolom Afdelings-ID van beide tabellen. Waar de DepartmentID van deze tabellen overeenkomen (dat wil zeggen dat aan het join-predikaat is voldaan), zal de query de kolommen LastName, DepartmentID en DepartmentName van de twee tabellen combineren tot een resultaatrij. Als de DepartmentID niet overeenkomt, wordt er geen resultaatrij gegenereerd.
Het resultaat van de uitvoering van de bovenstaande zoekopdracht is dus:
Employee.LastName | Employee.DepartmentID | Department.DepartmentName |
---|---|---|
Robinson | 34 | Administratief |
Jones | 33 | Techniek |
Smith | 34 | Administratief |
Heisenberg | 33 | Engineering |
Rafferty | 31 | Verkoop |
De werknemer “Williams” en de afdeling “Marketing” verschijnen niet in de resultaten van de query-uitvoering. Geen van beide heeft overeenkomende rijen in de andere respectievelijke tabel: “Williams” heeft geen bijbehorende afdeling en geen enkele medewerker heeft de afdelings-ID 35 (“Marketing”). Afhankelijk van de gewenste resultaten kan dit gedrag een subtiele fout zijn, die kan worden vermeden door de inner join te vervangen door een outer join.
Inner join en NULL-waarden Bewerken
Programmeurs zouden moeten nemen speciale zorg bij het samenvoegen van tabellen op kolommen die NULL-waarden kunnen bevatten, aangezien NULL nooit een andere waarde zal matchen (zelfs niet NULL zelf), tenzij de join-voorwaarde expliciet een combinatiepredikaat gebruikt dat eerst controleert of de joins-kolommen voor het toepassen van de resterende predikaatvoorwaarde (n). De Inner Join kan alleen veilig worden gebruikt in een database die referentiële integriteit afdwingt of waar de join-kolommen gegarandeerd niet NULL zijn. Veel relationele databases voor transactieverwerking vertrouwen op Atomicity, Consistentie, Isolatie, Duurzaamheid (ACID) standaarden voor gegevensupdate om de gegevensintegriteit te waarborgen, waardoor inner joins een geschikte keuze is. Transactiedatabases hebben echter meestal ook gewenste join-kolommen die NULL mogen zijn.Veel rapporterende relationele databases en datawarehouses gebruiken grote hoeveelheden Extract, Transform, Load (ETL) batchupdates die het moeilijk of onmogelijk maken om referentiële integriteit af te dwingen, wat resulteert in mogelijk NULL join-kolommen die een SQL-queryauteur niet kan wijzigen en waardoor inner joins worden weggelaten gegevens zonder indicatie van een fout. De keuze om een inner join te gebruiken, hangt af van het databaseontwerp en de gegevenskenmerken. Een linksbuiten-join kan meestal worden vervangen door een inner-join wanneer de join-kolommen in een tabel NULL-waarden kunnen bevatten.
Elke gegevenskolom die NULL (leeg) kan zijn, mag nooit als link in een tabel worden gebruikt. inner join, tenzij het beoogde resultaat is om de rijen met de NULL-waarde te verwijderen. Als NULL-join-kolommen opzettelijk uit de resultatenset moeten worden verwijderd, kan een inner-join sneller zijn dan een outer-join, omdat de tabel-join en filtering in één stap worden uitgevoerd. Omgekeerd kan een inner join resulteren in rampzalig trage prestaties of zelfs een servercrash wanneer deze wordt gebruikt in een query met een groot volume in combinatie met databasefuncties in een SQL Where-component. Een functie in een SQL Where-component kan ertoe leiden dat de database relatief compacte tabelindexen negeert. De database kan de geselecteerde kolommen van beide tabellen lezen en innerlijk samenvoegen voordat het aantal rijen wordt verminderd met behulp van het filter dat afhankelijk is van een berekende waarde, wat resulteert in een relatief enorme hoeveelheid inefficiënte verwerking.
Wanneer een resultaatset wordt geproduceerd door verschillende tabellen samen te voegen, inclusief hoofdtabellen die worden gebruikt om volledige tekstbeschrijvingen van numerieke identificatiecodes op te zoeken (een opzoektabel), een NULL-waarde in een van de externe sleutels kan ertoe leiden dat de hele rij uit de resultatenset wordt verwijderd, zonder indicatie van fouten. Een complexe SQL-query die een of meer inner joins en meerdere outer joins bevat, heeft hetzelfde risico voor NULL-waarden in de innerlijke join-linkkolommen.
Een toewijding aan SQL-code die inner joins bevat, gaat ervan uit dat NULL-join-kolommen niet worden geïntroduceerd door toekomstige wijzigingen, inclusief updates van leveranciers, ontwerpwijzigingen en bulkverwerking buiten de gegevensvalidatieregels van de applicatie, zoals dataconversies, migraties, bulkimporten en samenvoegingen.
Men kan inner joins verder classificeren als equi-joins, als natuurlijke joins of als cross-joins.
Equi-joinEdit
Een equi-join is een specifiek type op comparator gebaseerde join, die alleen gelijkheidsvergelijkingen gebruikt in het join-predikaat. Het gebruik van andere vergelijkingsoperatoren (zoals <
) diskwalificeert een join als een equi-join. De bovenstaande zoekopdracht geeft al een voorbeeld van een equi-join:
SELECT *FROM employee JOIN department ON employee.DepartmentID = department.DepartmentID;
We kunnen equi-join schrijven zoals hieronder,
SELECT *FROM employee, departmentWHERE employee.DepartmentID = department.DepartmentID;
Als co lumns in een equi-join hebben dezelfde naam, SQL-92 biedt een optionele verkorte notatie voor het uitdrukken van equi-joins, door middel van de USING
constructie:
SELECT