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 *FROM employee INNER JOIN department USING (DepartmentID);

De USING -constructie is echter meer dan louter syntactische suiker, aangezien de resultatenset verschilt van het resultaat set van de versie met het expliciete predikaat. In het bijzonder zullen alle kolommen die worden genoemd in de USING lijst slechts één keer verschijnen, met een niet-gekwalificeerde naam, in plaats van één keer voor elke tabel in de join. In het bovenstaande geval is er een enkele DepartmentID kolom en geen employee.DepartmentID of department.DepartmentID .

De USING -clausule wordt niet ondersteund door MS SQL Server en Sybase.

Natuurlijke joinEdit

De natuurlijke join is een speciaal geval van equi-join. Natuurlijke join (⋈) is een binaire operator die wordt geschreven als (R ⋈ S) waarbij R en S relaties zijn. Het resultaat van de natuurlijke join is de verzameling van alle combinaties van tupels in R en S die gelijk zijn op hun gemeenschappelijke attribuutnamen.Bekijk voor een voorbeeld de tabellen Werknemer en Afdeling en hun natuurlijke deelname:

Medewerker
Naam EmpId DeptName
Harry 3415 Financiën
Sally 2241 Verkoop
George 3401 Financiën
Harriet 2202 Verkoop
Afdeling
DeptName Manager
Financiën George
Verkoop Harriet
Productie Charles
Medewerker ⋈ {\ displaystyle \ bowtie} Dept
Name EmpId DeptName Manager
Harry 3415 Financiën George
Sally 2241 Verkoop Harriet
George 3401 Financiën George
Harriet 2202 Verkoop Harriet

Dit kan ook worden gebruikt om de samenstelling van relaties te definiëren. De samenstelling van Employee en Dept is bijvoorbeeld hun join zoals hierboven weergegeven, geprojecteerd op alles behalve het gemeenschappelijke attribuut DeptName. In categorietheorie is de join precies het vezelproduct.

De natuurlijke join is misschien wel een van de belangrijkste operatoren, aangezien het de relationele tegenhanger is van logische AND. Merk op dat als dezelfde variabele voorkomt in elk van de twee predikaten die zijn verbonden door AND, die variabele voor hetzelfde staat en beide verschijningen altijd moeten worden vervangen door dezelfde waarde. In het bijzonder maakt de natuurlijke join de combinatie mogelijk van relaties die zijn geassocieerd met een externe sleutel. In het bovenstaande voorbeeld bevat bijvoorbeeld een externe sleutel waarschijnlijk van Employee.DeptName naar Dept.DeptName en vervolgens combineert de natuurlijke toetreding van Employee en Dept alle medewerkers met hun afdelingen. Dit werkt omdat de externe sleutel geldt tussen attributen met dezelfde naam. Als dit niet het geval is, zoals in de externe sleutel van Dept.manager naar Employee.Name, dan moeten deze kolommen hernoemd worden voordat de natuurlijke join wordt genomen. Een dergelijke join wordt ook wel equi-join genoemd.

Meer formeel wordt de semantiek van de natuurlijke join als volgt gedefinieerd:

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 \}},

waarbij Fun een predikaat is dat waar is voor een relatie r als en slechts als r een functie is. Gewoonlijk is het vereist dat R en S ten minste één gemeenschappelijk kenmerk moeten hebben, maar als deze beperking wordt weggelaten en R en S geen gemeenschappelijke kenmerken hebben, wordt de natuurlijke verbinding precies het Cartesiaanse product.

natuurlijke join kan als volgt worden gesimuleerd met de primitieven van Codd. Laat c1, …, cm de attribuutnamen zijn die gemeenschappelijk zijn voor R en S, r1, …, rn de attribuutnamen zijn die uniek zijn voor R en laat s1, …, sk de attributen die uniek zijn voor S. Ga er verder van uit dat de attribuutnamen x1,…, xm noch in R noch in S. voorkomen. In een eerste stap kunnen de gemeenschappelijke attribuutnamen in S nu hernoemd worden:

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))}

Vervolgens nemen we het Cartesiaans product en selecteren de tupels die moeten worden samengevoegd:

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)}

Een natuurlijke join is een soort equi- join waar het join-predicaat impliciet ontstaat door alle kolommen in beide tabellen te vergelijken die dezelfde kolomnamen hebben in de samengevoegde tabellen. De resulterende samengevoegde tabel bevat slechts één kolom voor elk paar kolommen met dezelfde naam. In het geval dat er geen kolommen met dezelfde namen worden gevonden, is het resultaat een cross-join.

De meeste experts zijn het erover eens dat NATURAL JOINs gevaarlijk zijn en daarom sterk ontmoedigen het gebruik ervan. Het gevaar komt voort uit het onbedoeld toevoegen van een nieuwe kolom met dezelfde naam als een andere kolom in de andere tabel. Een bestaande natuurlijke join kan dan “natuurlijk” de nieuwe kolom gebruiken voor vergelijkingen, waardoor vergelijkingen / overeenkomsten worden gemaakt met andere criteria (uit verschillende kolommen) dan voorheen. Een bestaande query kan dus verschillende resultaten opleveren, ook al zijn de gegevens in de tabellen niet gewijzigd, maar alleen aangevuld.Het gebruik van kolomnamen om automatisch tabelkoppelingen te bepalen is geen optie in grote databases met honderden of duizenden tabellen, waar het een onrealistische beperking oplegt aan naamgevingsconventies. Real-world databases zijn gewoonlijk ontworpen met externe sleuteldata die niet consistent worden gevuld (NULL-waarden zijn toegestaan) vanwege bedrijfsregels en context. Het is gebruikelijk om kolomnamen van vergelijkbare gegevens in verschillende tabellen te wijzigen en dit gebrek aan starre consistentie degradeert natuurlijke joins naar een theoretisch concept voor discussie.

De bovenstaande voorbeeldquery voor inner joins kan worden uitgedrukt als een natuurlijke doe op de volgende manier mee:

SELECT *FROM employee NATURAL JOIN department;

Net als bij de expliciete USING clausule, er komt slechts één DepartmentID-kolom voor in de samengevoegde tabel, zonder kwalificatie:

DepartmentID Werknemer.Lastnaam Afdelingsnaam
34 Smit Administratief
33 Jones Techniek
34 Robinson Administratief
33 Heisenberg Techniek
31 Rafferty Verkoop

PostgreSQL, MySQL en Oracle su pport natuurlijke joins; Microsoft T-SQL en IBM DB2 doen dat niet. De kolommen die in de join worden gebruikt, zijn impliciet, dus de join-code geeft niet aan welke kolommen worden verwacht, en een wijziging in kolomnamen kan de resultaten wijzigen. In de SQL: 2011-standaard maken natuurlijke joins deel uit van het optionele pakket F401, “Uitgebreide samengevoegde tabel”.

In veel databaseomgevingen worden de kolomnamen beheerd door een externe leverancier, niet door de ontwikkelaar van de query. Een natuurlijke join veronderstelt stabiliteit en consistentie in kolomnamen die kunnen veranderen tijdens door de leverancier voorgeschreven versie-upgrades.

Write a Comment

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *