We bevinden ons bij het derde artikel in de Oracle-migratiereeks. Deze keer kijken we naar die vreemde operators die de WHERE-clausulecriteria in Oracle (+) wijzigen. Net als al het andere heeft PostgreSQL daar een oplossing voor.
RIGHT JOIN
Oracle ondersteunt, en veel ontwikkelaars gebruiken, ANSI outer JOIN-syntaxis met behulp van operators voor de kwalificatieclausule.
Meestal ziet dat er ongeveer zo uit:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
Het doel van deze syntaxis is een rechter outer join. In termen van verzamelingentheorie is dit de subset inclusief alle plaatsen, ongeacht de persoon.
Het resultaat van een kleine steekproef zou er als volgt uitzien:
id | achternaam | first_name | id | locatie | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | Londen | 2 |
3 | Riggs | Simon | 3 | Parijs | 3 |
Deze syntaxis wordt niet ondersteund in PostgreSQL.
Om hetzelfde resultaat te bereiken, gebruikt u de standaard SQL-syntaxis voor outer joins.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL biedt ook een verduidelijkend bijwoord OUTER
. Deze verduidelijking is volledig optioneel, zoals elke RIGHT JOIN
is per definitie een OUTER
doe mee.
VOLLEDIGE JOIN
Evenzo werkt het gebruik van de Oracle-syntaxis voor een volledige join niet in PostgreSQL.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
Het doel van deze syntaxis is een volledige lijst van personen en plaatsen, ongeacht of een persoon aan een plaats is gekoppeld of niet.
Het resultaat ziet er als volgt uit:
id | achternaam | first_name** | id | locatie | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | Londen | 2 |
3 | Riggs | Simon | 3 | Parijs | 3 |
4 | Andrew | Dunstan | (NULL) | (NULL) | (NULL) |
Met behulp van de PostgreSQL-syntaxis zou de query als volgt worden geschreven:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
Nogmaals, de OUTER
zoekwoord is volledig optioneel.
CROSS JOIN
Een duidelijk voordeel van het gebruik van zoekwoorden in plaats van impliciete relaties is dat u niet per ongeluk een cross-product kunt maken.
De syntaxis:
SELECT *
FROM persons
LEFT JOIN places;
Zal resulteren in een fout:
ERROR: syntax error at or near ";"
Geeft aan dat de instructie niet compleet is bij de regeleindemarkering ";".
PostgreSQL zal het cross join-product maken met behulp van de ANSI-syntaxis.
SELECT *
FROM persons, places;
id | achternaam | voornaam | id | locatie | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrew | 1 | Dallas | (null) |
1 | Dunstan | Andrew | 2 | Londen | 2 |
1 | Dunstan | Andrew | 3 | Parijs | 3 |
1 | Dunstan | Andrew | 4 | Madrid | (null) |
2 | Koninklijke | Kirk | 1 | Dallas | (null) |
2 | Koninklijke | Kirk | 2 | Londen | 2 |
2 | Koninklijke | Kirk | 3 | Parijs | 3 |
2 | Koninklijke | Kirk | 4 | Madrid | (null) |
3 | Riggs | Simon | 1 | Dallas | (null) |
3 | Riggs | Simon | 2 | Londen | 2 |
3 | Riggs | Simon | 3 | Parijs | 3 |
3 | Riggs | Simon | 4 | Madrid | (null) |
6 | Wong | Markeren | 1 | Dallas | (null) |
6 | Wong | Markeren | 2 | Londen | 2 |
6 | Wong | Markeren | 3 | Parijs | 3 |
6 | Wong | Markeren | 4 | Madrid | (null) |
Dat is waarschijnlijker een codeerfout dan het opzettelijke resultaat.
Om deze functionaliteit opzettelijk te krijgen, wordt aanbevolen om de CROSS JOIN
. te gebruiken verklaring.
SELECT *
FROM persons
CROSS JOIN places;
Zo is het ondubbelzinnig wat er in de verklaring werd bedoeld.
NATUURLIJKE JOIN
PostgreSQL ondersteunt de NATURAL JOIN
syntaxis, maar een beetje onder protest.
SELECT *
FROM persons
NATURAL JOIN places;
Dit levert het volgende resultaat op.
id | achternaam | voornaam | ouder_id | locatie | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrew | (null) | Dallas | (null) |
2 | Koninklijke | Kirk | 1 | Londen | 2 |
3 | Riggs | Simon | 1 | Parijs | 3 |
Deze syntaxis is echter een probleem. Voor ons voorbeeld heeft de kolom "id" in beide tabellen niets met elkaar te maken . Deze samenvoeging heeft een resultaat opgeleverd, maar wel een met volledig irrelevante inhoud.
Bovendien kunt u een zoekopdracht hebben die in eerste instantie het juiste resultaat geeft, maar latere DDL-instructies hebben een stille invloed.
Overweeg:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Welke kolom is nu de NATURAL JOIN
gebruik makend van? De keuzes zijn id, places_id, person_id en al het bovenstaande. Ik laat het antwoord als oefening aan de lezer over.
Deze syntaxis is een tijdbom voor uw code. Gebruik het gewoon niet.
Oké, dus je bent niet overtuigd. Nou, dan heb je tenminste wat zinnige codeerconventies. Geef voor de bovenliggende tabel de identiteitskolom de naam "myparenttable_id". Wanneer u ernaar verwijst vanuit onderliggende relaties, gebruikt u dezelfde naam, "mijnoudertabel_id". Noem nooit iets "id", en verwijs nooit naar een kolom met een andere naam. Ach, vergeet het maar. Doe dit gewoon niet.
U kunt in de verleiding komen om de vorige puzzel ondubbelzinnig te maken door de USING
. te gebruiken trefwoord. Dat zou er zo uitzien:
SELECT *
FROM persons
JOIN places
USING (id);
Maar de USING
trefwoord kan alleen profiteren van exacte naamovereenkomsten in tabellen. Wat nogmaals, in ons voorbeeld is gewoon helemaal verkeerd.
De beste keuze voor PostgreSQL is om simpelweg het ontwerpen van tabellen te vermijden door conventiestandaarden te coderen.
Samenvatting
Deze trefwoordtechnieken (vs. operators) zijn ook beschikbaar op Oracle. Ze zijn meer platformonafhankelijk en minder dubbelzinnig. Dat alleen al zou hen tot de beste praktijken maken.
Daar komt nog bij dat ze logische fouten blootleggen bij oneigenlijk gebruik. Voor elke ontwikkeling in PostgreSQL raden we eenzijdig aan om expliciete trefwoorden te gebruiken.