Inleiding
Het splitsen van gerelateerde gegevens in afzonderlijke tabellen kan gunstig zijn vanuit het oogpunt van consistentie, flexibiliteit en bepaalde soorten prestaties. U hebt echter nog steeds een redelijke manier nodig om records opnieuw te integreren wanneer de relevante informatie meerdere tabellen omvat.
In relationele databases, wordt lid bieden een manier om de records in twee of meer tabellen te combineren op basis van gemeenschappelijke veldwaarden. Verschillende soorten samenvoegingen kunnen verschillende resultaten opleveren, afhankelijk van hoe niet-overeenkomende rijen moeten worden verwerkt. In deze handleiding bespreken we de verschillende soorten joins die PostgreSQL biedt en hoe u deze kunt gebruiken om tabelgegevens uit meerdere bronnen te combineren.
Wat zijn joins?
Kortom, wordt lid zijn een manier om gegevens uit meerdere tabellen weer te geven. Ze doen dit door records uit verschillende bronnen aan elkaar te koppelen op basis van overeenkomende waarden in bepaalde kolommen. Elke resulterende rij bestaat uit een record uit de eerste tabel gecombineerd met een rij uit de tweede tabel, gebaseerd op een of meer kolommen in elke tabel met dezelfde waarde.
De basissyntaxis van een join ziet er als volgt uit:
SELECT *FROM <first_table><join_type> <second_table> <join_condition>;
In een join wordt elke resulterende rij geconstrueerd door alle kolommen van de eerste tabel op te nemen, gevolgd door alle kolommen uit de tweede tabel. De SELECT
gedeelte van de zoekopdracht kan worden gebruikt om de exacte kolommen te specificeren die u wilt weergeven.
Er kunnen meerdere rijen worden samengesteld uit de originele tabellen als de waarden in de kolommen die voor vergelijking worden gebruikt niet uniek zijn. Stel u bijvoorbeeld voor dat u een kolom vergelijkt uit de eerste tabel die twee records heeft met de waarde "rood". Hiermee matcht een kolom uit de tweede tabel met drie rijen met die waarde. De samenvoeging zal zes verschillende rijen voor die waarde produceren die de verschillende combinaties vertegenwoordigen die kunnen worden bereikt.
Het type join en de join-voorwaarden bepalen hoe elke rij die wordt weergegeven, is opgebouwd. Dit heeft invloed op wat er gebeurt met de rijen van elke tabel die wel en niet niet . doen een match hebben op de deelnamevoorwaarde.
Gemakshalve matchen veel joins de primaire sleutel op de ene tabel met een bijbehorende externe sleutel op de tweede tabel. Hoewel primaire en externe sleutels alleen door het databasesysteem worden gebruikt om consistentiegaranties te behouden, maakt hun relatie ze vaak een goede kandidaat voor deelnamevoorwaarden.
Verschillende soorten joins
Er zijn verschillende soorten joins beschikbaar, die elk mogelijk verschillende resultaten opleveren. Als u begrijpt hoe elk type is opgebouwd, kunt u bepalen welk type geschikt is voor verschillende scenario's.
Inner join
De standaard join heet een inner join . In PostgreSQL kan dit worden gespecificeerd met INNER JOIN
of gewoon JOIN
.
Hier is een typisch voorbeeld dat de syntaxis van een inner join demonstreert:
SELECT *FROM table_1[INNER] JOIN table_2 ON table_1.id = table_2.table_1_id;
Een inner join is het meest beperkende type join omdat het alleen rijen weergeeft die zijn gemaakt door rijen uit elke tabel te combineren. Alle rijen in de samenstellende tabellen die geen overeenkomende tegenhanger in de andere tabel hadden, worden uit de resultaten verwijderd. Als de eerste tabel bijvoorbeeld de waarde 'blauw' heeft in de vergelijkingskolom en de tweede tabel geen record met die waarde heeft, wordt die rij onderdrukt in de uitvoer.
Als u de resultaten weergeeft als een Venn-diagram van de componententabellen, kunt u met een inner join het overlappende gebied van de twee cirkels weergeven. Geen van de waarden die alleen in een van de tabellen bestonden, wordt weergegeven.
Linker join
Een left join is een join die alle records toont die in een inner join zijn gevonden, plus alle niet-overeenkomende rijen van de eerste tabel. In PostgreSQL kan dit worden gespecificeerd als een LEFT OUTER JOIN
of gewoon een LEFT JOIN
.
De basissyntaxis van een left join volgt dit patroon:
SELECT *FROM table_1LEFT JOIN table_2 ON table_1.id = table_2.table_1_id;
Een left join wordt gemaakt door eerst een inner join uit te voeren om rijen te construeren uit alle overeenkomende records in beide tabellen. Daarna worden ook de ongeëvenaarde records uit de eerste tabel meegenomen. Aangezien elke rij in een join de kolommen van beide tabellen bevat, gebruiken de niet-overeenkomende kolommen NULL
als de waarde voor alle kolommen in de tweede tabel.
Als u de resultaten weergeeft als een Venn-diagram van de componententabellen, kunt u met een left join de hele linkercirkel voorstellen. De delen van de linker cirkel die worden vertegenwoordigd door het snijpunt tussen de twee cirkels zullen aanvullende gegevens bevatten, aangevuld met de rechter tabel.
Right join
Een juiste join is een join die alle records toont die in een inner join zijn gevonden, plus alle niet-overeenkomende rijen uit de tweede tabel. In PostgreSQL kan dit worden gespecificeerd als een RIGHT OUTER JOIN
of gewoon een RIGHT JOIN
.
De basissyntaxis van een right join volgt dit patroon:
SELECT *FROM table_1RIGHT JOIN table_2 ON table_1.id = table_2.table_1_id;
Een rechter join wordt gemaakt door eerst een inner join uit te voeren om rijen te construeren uit alle overeenkomende records in beide tabellen. Daarna worden ook de ongeëvenaarde records uit de tweede tabel meegenomen. Aangezien elke rij in een join de kolommen van beide tabellen bevat, gebruiken de niet-overeenkomende kolommen NULL
als de waarde voor alle kolommen in de eerste tabel.
Als u de resultaten weergeeft als een Venn-diagram van de componententabellen, kunt u met een right join de hele rechtercirkel weergeven. De delen van de rechtercirkel die worden vertegenwoordigd door het snijpunt tussen de twee cirkels zullen aanvullende gegevens bevatten, aangevuld met de linkertabel.
Volledige deelname
Een volledige join is een join die alle records toont die in een inner join zijn gevonden, plus alle niet-overeenkomende rijen uit beide componenttabellen. In PostgreSQL kan dit worden gespecificeerd als een FULL OUTER JOIN
of gewoon een FULL JOIN
.
De basissyntaxis van een volledige join volgt dit patroon:
SELECT *FROM table_1FULL JOIN table_2 ON table_1.id = table_2.table_1_id;
Een volledige join wordt gemaakt door eerst een inner join uit te voeren om rijen te construeren uit alle overeenkomende records in beide tabellen. Daarna worden ook de ongeëvenaarde records uit beide tabellen meegenomen. Aangezien elke rij in een join de kolommen van beide tabellen bevat, gebruiken de niet-overeenkomende kolommen NULL
als de waarde voor alle kolommen in de ongeëvenaarde andere tabel.
Als u de resultaten weergeeft als een Venn-diagram van de componenttabellen, stelt een volledige join u in staat om beide componentcirkels volledig weer te geven. Het snijpunt van de twee cirkels heeft waarden die worden geleverd door elk van de samenstellende tabellen. De delen van de cirkels buiten het overlappende gebied hebben de waarden uit de tabel waar ze bij horen, met behulp van NULL
om de kolommen in de andere tabel in te vullen.
Cross-join
Een speciale join genaamd een CROSS JOIN
is ook beschikbaar. Een cross join gebruikt geen vergelijkingen om te bepalen of de rijen in elke tabel met elkaar overeenkomen. In plaats daarvan worden de resultaten samengesteld door eenvoudigweg elk van de rijen van de eerste tabel toe te voegen aan elk van de rijen van de tweede tabel.
Dit levert een Cartesiaans product op van de rijen in twee of meer tabellen. In feite combineert deze stijl van samenvoegen rijen uit elke tabel onvoorwaardelijk. Dus als elke tabel drie rijen heeft, zou de resulterende tabel negen rijen hebben die alle kolommen van beide tabellen bevatten.
Als u bijvoorbeeld een tabel heeft met de naam t1
gecombineerd met een tabel genaamd t2
, elk met rijen r1
, r2
, en r3
, het resultaat zou negen rijen zijn, als volgt gecombineerd:
t1.r1 + t2.r1t1.r1 + t2.r2t1.r1 + t2.r3t1.r2 + t2.r1t1.r2 + t2.r2t1.r2 + t2.r3t1.r3 + t2.r1t1.r3 + t2.r2t1.r3 + t2.r3
Self join
Een self-join is elke join die de rijen van een tabel met zichzelf combineert. Het is misschien niet meteen duidelijk hoe dit nuttig kan zijn, maar het heeft eigenlijk veel algemene toepassingen.
Tabellen beschrijven vaak entiteiten die in relatie tot elkaar meerdere rollen kunnen vervullen. Als u bijvoorbeeld een tabel heeft met people
, elke rij kan mogelijk een mother
bevatten kolom die verwijst naar andere people
in de tafel. Met een self-join kunt u deze verschillende rijen samenvoegen door een tweede exemplaar van de tabel samen te voegen met de eerste waar deze waarden overeenkomen.
Aangezien self-joins twee keer naar dezelfde tabel verwijzen, zijn tabelaliassen vereist om de verwijzingen ondubbelzinnig te maken. In het bovenstaande voorbeeld zou je bijvoorbeeld de twee instanties van de people
. kunnen samenvoegen tabel met de aliassen people AS children
en people AS mothers
. Op die manier kunt u specificeren naar welke instantie van de tabel u verwijst bij het definiëren van join-voorwaarden.
Hier is nog een voorbeeld, dit keer voor relaties tussen werknemers en managers:
SELECT *FROM people AS employeeJOIN people AS manager ON employee.manager_id = manager.id;
Deelnamevoorwaarden
Bij het combineren van tabellen bepaalt de join-voorwaarde hoe rijen aan elkaar worden gekoppeld om de samengestelde resultaten te vormen. Het uitgangspunt is om de kolommen in elke tabel te definiëren die moeten overeenkomen om de join op die rij te laten plaatsvinden.
De ON
clausule
De meest standaard manier om de voorwaarden voor tabeljoins te definiëren is met de ON
clausule. De ON
clausule gebruikt een isgelijkteken om de exacte kolommen van elke tabel op te geven die worden vergeleken om te bepalen wanneer een join kan plaatsvinden. PostgreSQL gebruikt de geleverde kolommen om de rijen van elke tabel aan elkaar te naaien.
De ON
clausule is de meest uitgebreide, maar ook de meest flexibele van de beschikbare toetredingsvoorwaarden. Het zorgt voor specificiteit, ongeacht hoe gestandaardiseerd de kolomnamen zijn van elke tabel die wordt gecombineerd.
De basissyntaxis van de ON
clausule ziet er als volgt uit:
SELECT *FROM table1JOIN table2ON table1.id = table2.ident;
Hier, de rijen van table1
en table2
zal worden toegevoegd wanneer de id
kolom uit table1
komt overeen met de ident
kolom uit table2
. Omdat er een inner join wordt gebruikt, tonen de resultaten alleen de rijen die zijn samengevoegd. Aangezien de zoekopdracht het jokerteken *
. gebruikt teken, worden alle kolommen van beide tabellen weergegeven.
Dit betekent dat zowel de id
kolom uit table1
en de ident
kolom uit table2
worden weergegeven, ook al hebben ze exact dezelfde waarde omdat ze aan de join-voorwaarde voldoen. U kunt deze duplicatie voorkomen door de exacte kolommen op te roepen die u wilt weergeven in de SELECT
kolommenlijst.
De USING
clausule
De USING
clausule is een afkorting voor het specificeren van de voorwaarden van een ON
clausule die kan worden gebruikt wanneer de kolommen die worden vergeleken dezelfde naam hebben in beide tabellen. De USING
clausule neemt een lijst, tussen haakjes, van de gedeelde kolomnamen die moeten worden vergeleken.
De algemene syntaxis van de USING
clausule gebruikt dit formaat:
SELECT *FROM table1JOIN table2USING (id, state);
Deze join combineert table1
met table2
wanneer twee kolommen die beide tabellen delen (id
en state
) hebben elk overeenkomende waarden.
Deze zelfde join kan uitgebreider worden uitgedrukt met ON
zoals dit:
SELECT *FROM table1JOIN table2ON table1.id = table2.id AND table1.state = table2.state;
Hoewel beide bovenstaande joins ertoe zouden leiden dat dezelfde rijen worden geconstrueerd met dezelfde aanwezige gegevens, zouden ze iets anders worden weergegeven. Terwijl de ON
clausule bevat alle kolommen van beide tabellen, de USING
clausule onderdrukt de dubbele kolommen. Dus in plaats van twee aparte id
kolommen en twee aparte state
kolommen (één voor elke tabel), zouden de resultaten slechts één van elk van de gedeelde kolommen hebben, gevolgd door alle andere kolommen die worden geleverd door table1
en table2
.
De NATURAL
clausule
De NATURAL
clausule is nog een andere afkorting die de breedsprakigheid van de USING
. verder kan verminderen clausule. Een NATURAL
join specificeert geen kolommen te matchen. In plaats daarvan voegt PostgreSQL automatisch de tabellen samen op basis van alle kolommen die overeenkomende kolommen in elke database hebben.
De algemene syntaxis van de NATURAL
join-clausule ziet er als volgt uit:
SELECT *FROM table1NATURAL JOIN table2;
Ervan uitgaande dat table1
en table2
beide hebben kolommen met de naam id
, state
, en company
, zou de bovenstaande zoekopdracht gelijk zijn aan deze zoekopdracht met de ON
clausule:
SELECT *FROM table1JOIN table2ON table1.id = table2.id AND table1.state = table2.state AND table1.company = table2.company;
En deze zoekopdracht met de USING
clausule:
SELECT *FROM table1JOIN table2USING (id, state, company);
Zoals de USING
clausule, de NATURAL
clausule onderdrukt dubbele kolommen, zodat er slechts één exemplaar van elk van de samengevoegde kolommen in de resultaten zou zijn.
Terwijl de NATURAL
clausule de breedsprakigheid van uw vragen kan verminderen, moet u voorzichtig zijn bij het gebruik ervan. Omdat de kolommen die worden gebruikt om de tabellen samen te voegen automatisch worden berekend, kunnen de resultaten enorm verschillen als de kolommen in de componenttabellen veranderen als gevolg van nieuwe join-voorwaarden.
Deelnamevoorwaarden en de WHERE
clausule
Deelnamevoorwaarden hebben veel kenmerken gemeen met de vergelijkingen die worden gebruikt om rijen gegevens te filteren met behulp van WHERE
clausules. Beide constructies definiëren expressies die moeten worden geëvalueerd als waar om de rij te overwegen. Hierdoor is het niet altijd intuïtief wat het verschil is tussen het opnemen van extra vergelijkingen in een WHERE
construeren versus ze definiëren binnen de join-clausule zelf.
Om de verschillen te begrijpen die zullen resulteren, moeten we kijken naar de volgorde waarin PostgreSQL verschillende delen van een query verwerkt. In dit geval worden de predikaten in de join-voorwaarde eerst verwerkt om de virtuele samengevoegde tabel in het geheugen te construeren. Na deze fase worden de uitdrukkingen binnen de WHERE
clausule worden geëvalueerd om de resulterende rijen te filteren.
Stel bijvoorbeeld dat we twee tabellen hebben met de naam customer
en order
die we moeten samenvoegen. We willen de twee tabellen samenvoegen door de customer.id
kolom met de order.customer_id
kolom. Daarnaast zijn we geïnteresseerd in de rijen in de order
tabel met een product_id
van 12345.
Gezien de bovenstaande vereisten, hebben we twee voorwaarden waar we om geven. De manier waarop we deze voorwaarden uitdrukken, bepaalt echter de resultaten die we ontvangen.
Laten we eerst beide gebruiken als deelnamevoorwaarden voor een LEFT JOIN
:
SELECT customer.id AS customer_id, customer.name, order.id AS order_id, order.product_idFROM customerLEFT JOIN orderON customer.id = order.customer_id AND order.product_id = 12345;
De resultaten kunnen er mogelijk ongeveer zo uitzien:
customer_id | name | order_id | product_id ------------+----------+----------+------------ 4380 | Acme Co | 480 | 12345 4380 | Acme Co | 182 | 12345 320 | Other Co | 680 | 12345 4380 | Acme Co | | 320 | Other Co | | 20 | Early Co | | 8033 | Big Co | |(7 rows)
PostgreSQL kwam tot dit resultaat door de volgende bewerkingen uit te voeren:
- Combineer alle rijen in de
customer
tabel met deorder
tabel waar:customer.id
komt overeen metorder.customer_id
.order.product_id
komt overeen met 12345
- Omdat we een left-join gebruiken, moet u alle niet-overeenkomende . opnemen rijen uit de linkertabel (
customer
), vul de kolommen uit de rechtertabel uit (order
) metNULL
waarden. - Alleen de kolommen weergeven die worden vermeld in de
SELECT
kolomspecificatie.
Het resultaat is dat al onze samengevoegde rijen voldoen aan beide voorwaarden waarnaar we op zoek zijn. De linker join zorgt er echter voor dat PostgreSQL ook alle rijen uit de eerste tabel opneemt die niet aan de join-voorwaarde voldeden. Dit resulteert in "overgebleven" rijen die de schijnbare bedoeling van de zoekopdracht niet lijken te volgen.
Als we de tweede zoekopdracht (order.product_id
=12345) naar een WHERE
clausule, in plaats van het op te nemen als een join-voorwaarde, krijgen we verschillende resultaten:
SELECT customer.id AS customer_id, customer.name, order.id AS order_id, order.product_idFROM customerLEFT JOIN orderON customer.id = order.customer_idWHERE order.product_id = 12345;
Deze keer worden er slechts drie rijen weergegeven:
customer_id | name | order_id | product_id ------------+----------+----------+------------ 4380 | Acme Co | 480 | 12345 4380 | Acme Co | 182 | 12345 320 | Other Co | 680 | 12345(3 rows)
De volgorde waarin de vergelijkingen worden uitgevoerd, is de reden voor deze verschillen. Deze keer verwerkt PostgreSQL de query als volgt:
- Combineer alle rijen in de
customer
tabel met deorder
tabel waarcustomer.id
komt overeen metorder.customer_id
. - Omdat we een left-join gebruiken, moet u alle niet-overeenkomende . opnemen rijen uit de linkertabel (
customer
), vul de kolommen uit de rechtertabel uit (order
) metNULL
waarden. - Evalueer de
WHERE
clausule om alle rijen te verwijderen die geen 12345 hebben als de waarde voor deorder.product_id
kolom. - Alleen de kolommen weergeven die worden vermeld in de
SELECT
kolomspecificatie.
Deze keer, ook al gebruiken we een left join, de WHERE
clausule kapt de resultaten af door alle rijen weg te filteren zonder de juiste product_id
. Omdat niet-overeenkomende rijen product_id
. zouden hebben ingesteld op NULL
, worden hiermee alle niet-overeenkomende rijen verwijderd die zijn ingevuld door de linker join. Het verwijdert ook alle rijen die overeenkomen met de deelnamevoorwaarde die deze tweede controleronde niet hebben doorstaan.
Als u het basisproces begrijpt dat PostgreSQL gebruikt om uw query's uit te voeren, kunt u enkele gemakkelijk te maken maar moeilijk te debuggen fouten voorkomen terwijl u met uw gegevens werkt.
Conclusie
In deze handleiding hebben we besproken hoe met joins relationele databases gegevens uit verschillende tabellen kunnen combineren om waardevollere antwoorden te bieden. We hebben gesproken over de verschillende joins die PostgreSQL ondersteunt, de manier waarop elk type zijn resultaten verzamelt en wat u kunt verwachten bij het gebruik van specifieke soorten joins. Daarna hebben we verschillende manieren besproken om join-voorwaarden te definiëren en hebben we gekeken naar het samenspel tussen joins en de WHERE
clausule kan tot verrassingen leiden.
Joins zijn een essentieel onderdeel van wat relationele databases krachtig en flexibel genoeg maakt om zoveel verschillende soorten query's te verwerken. Door gegevens te ordenen met gebruikmaking van logische grenzen en toch in staat te zijn de gegevens per geval op nieuwe manieren te recombineren, krijgen relationele databases zoals PostgreSQL een ongelooflijke veelzijdigheid. Door te leren hoe u deze samenvoeging tussen tabellen kunt uitvoeren, kunt u complexere zoekopdrachten maken en vertrouwen op de database om volledige afbeeldingen van uw gegevens te maken.