Vi befinder os i den tredje artikel i Oracle-migreringsserien. Denne gang ser vi på de mærkelige operatorer, der ændrer WHERE-sætningskriterierne i Oracle (+). Som alt andet har PostgreSQL en løsning til det.
HØJRE JOIN
Oracle understøtter, og mange udviklere bruger, ANSI ydre JOIN-syntaks ved hjælp af operatorer til kvalifikationsklausulen.
Typisk ser det sådan ud:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
Formålet med denne syntaks er en højre ydre sammenføjning. I mængdeteoretiske termer er dette delmængden inklusive alle steder, uanset person.
Resultatet af en lille prøve ville se sådan ud:
id | efternavn | fornavn | id | placering | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | London | 2 |
3 | Riggs | Simon | 3 | Paris | 3 |
Denne syntaks er ikke understøttet i PostgreSQL.
For at opnå det samme resultat, ville du bruge standard SQL-syntaks for outer joins.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL giver også et opklarende adverbium OUTER
. Denne clarifier er fuldstændig valgfri, som enhver RIGHT JOIN
er per definition en OUTER
deltage.
FULD JOIN
På samme måde virker det ikke i PostgreSQL at bruge Oracle-syntaksen til en fuld joinforbindelse.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
Formålet med denne syntaks er en komplet liste over personer og steder, uanset om en person er forbundet med et sted eller ej.
Resultatet vil gerne være sådan her:
id | efternavn | fornavn** | id | placering | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | London | 2 |
3 | Riggs | Simon | 3 | Paris | 3 |
4 | Andrew | Dunstan | (NULL) | (NULL) | (NULL) |
Ved at bruge PostgreSQL-syntaks ville forespørgslen blive skrevet således:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
Igen, OUTER
søgeord er helt valgfrit.
CROSS JOIN
En klar fordel ved tilgangen til at bruge søgeord frem for implicitte relationer er, at du ikke ved et uheld er i stand til at skabe et krydsprodukt.
Syntaksen:
SELECT *
FROM persons
LEFT JOIN places;
Vil resultere i en fejl:
ERROR: syntax error at or near ";"
Indikerer, at sætningen ikke er komplet ved linjeafslutningsmarkøren ";".
PostgreSQL vil oprette cross join-produktet ved hjælp af ANSI-syntaksen.
SELECT *
FROM persons, places;
id | efternavn | fornavn | id | placering | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrew | 1 | Dallas | (nul) |
1 | Dunstan | Andrew | 2 | London | 2 |
1 | Dunstan | Andrew | 3 | Paris | 3 |
1 | Dunstan | Andrew | 4 | Madrid | (nul) |
2 | Roybal | Kirk | 1 | Dallas | (nul) |
2 | Roybal | Kirk | 2 | London | 2 |
2 | Roybal | Kirk | 3 | Paris | 3 |
2 | Roybal | Kirk | 4 | Madrid | (nul) |
3 | Riggs | Simon | 1 | Dallas | (nul) |
3 | Riggs | Simon | 2 | London | 2 |
3 | Riggs | Simon | 3 | Paris | 3 |
3 | Riggs | Simon | 4 | Madrid | (nul) |
6 | Wong | Mærk | 1 | Dallas | (nul) |
6 | Wong | Mærk | 2 | London | 2 |
6 | Wong | Mærk | 3 | Paris | 3 |
6 | Wong | Mærk | 4 | Madrid | (nul) |
Hvilket er mere sandsynligt en kodefejl end det tilsigtede resultat.
For at få denne funktionalitet med vilje, anbefales det at bruge CROSS JOIN
erklæring.
SELECT *
FROM persons
CROSS JOIN places;
Dermed er det utvetydigt, hvad der menes i erklæringen.
NATURLIG JOIN
PostgreSQL understøtter NATURAL JOIN
syntaks, men lidt under protest.
SELECT *
FROM persons
NATURAL JOIN places;
Dette giver følgende resultat.
id | efternavn | fornavn | parent_id | placering | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrew | (nul) | Dallas | (nul) |
2 | Roybal | Kirk | 1 | London | 2 |
3 | Riggs | Simon | 1 | Paris | 3 |
Denne syntaks er dog et problem. For vores eksempel har "id"-kolonnen i begge tabeller intet med hinanden at gøre . Denne deltagelse har givet et resultat, men et med fuldstændig irrelevant indhold.
Derudover har du muligvis en forespørgsel, der til at begynde med præsenterer det korrekte resultat, men efterfølgende DDL-sætninger påvirker lydløst.
Overvej:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Hvilken kolonne er nu NATURAL JOIN
ved brug af? Valgene er id, steder_id, person_id og alle ovenstående. Jeg overlader svaret som en øvelse til læseren.
Denne syntaks er en tidsindstillet bombe for din kode. Bare lad være med at bruge det.
Ok, så du er ikke overbevist. Nå, så har du i det mindste nogle fornuftige kodningskonventioner. For den overordnede tabel skal du navngive identitetskolonnen "myparenttable_id". Når du refererer til det fra underordnede relationer, skal du bruge det samme navn, "myparenttable_id". Navngiv aldrig noget "id", og giv aldrig en henvisning til en kolonne med et andet navn. Ah, glem det. Bare lad være med at gøre dette.
Du kan blive fristet til at udelukke det forrige puslespil ved at bruge USING
søgeord. Det ville se sådan ud:
SELECT *
FROM persons
JOIN places
USING (id);
Men USING
søgeord kan kun drage fordel af eksakte navnematches på tværs af tabeller. Hvilket igen i vores eksempel bare er helt forkert.
Det bedste valg for PostgreSQL er simpelthen at undgå at designe tabeller ved at kode konventionsstandarder.
Oversigt
Disse søgeordsteknikker (i forhold til operatører) er også tilgængelige på Oracle. De er mere på tværs af platforme og mindre tvetydige. Det alene ville gøre dem til bedste praksis.
Derudover afslører de logiske fejl, når de bruges forkert. For enhver udvikling i PostgreSQL anbefaler vi ensidigt at bruge eksplicitte søgeord.