sql >> Databasteknik >  >> RDS >> PostgreSQL

Oracle till PostgreSQL:ANSI yttre kopplingssyntax i PostgreSQL

Vi befinner oss i den tredje artikeln i Oracle-migreringsserien. Den här gången tittar vi på de konstiga operatorerna som modifierar WHERE-satskriterierna i Oracle (+). Som allt annat har PostgreSQL en lösning för det.

HÖGER JOIN

Oracle stöder, och många utvecklare använder, ANSI yttre JOIN-syntax med operatorer till kvalifikationsklausulen.

Vanligtvis ser det ut ungefär så här:

SELECT *
FROM person, places
WHERE person.id = places.person_id(+)

Syftet med denna syntax är en höger yttre sammanfogning. I mängdteoretiska termer är detta delmängden som inkluderar alla platser, oavsett person.

Resultatet av ett litet urval skulle se ut så här:

id efternamn förnamn id plats person_id
1 (NULL) (NULL) 1 Dallas (NULL)
2 Roybal Kirk 2 London 2
3 Riggs Simon 3 Paris 3

Denna syntax stöds inte i PostgreSQL.

För att uppnå samma resultat skulle du använda standard SQL-syntax för yttre kopplingar.

SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;

SQL tillhandahåller också ett förtydligande adverb OUTER . Detta förtydligande är helt valfritt, som alla RIGHT JOIN är per definition en OUTER gå med.

FULLSTÄNDIG JOIN

På samma sätt fungerar inte Oracle-syntaxen för en fullständig koppling i PostgreSQL.

SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);

Syftet med denna syntax är en fullständig lista över personer och platser oavsett om en person är associerad med en plats eller inte.

Resultatet skulle vara så här:

id efternamn förnamn** id plats 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)

Med PostgreSQL-syntax skulle frågan skrivas så här:

SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;

Återigen, OUTER sökord är helt valfritt.

KORS JOIN

En tydlig fördel med tillvägagångssättet att använda sökord snarare än implicita relationer är att du inte av misstag kan skapa en korsprodukt.

Syntaxen:

SELECT *
FROM persons
LEFT JOIN places;

Kommer att resultera i ett fel:

ERROR:  syntax error at or near ";"

Indikerar att påståendet inte är komplett vid radslutmarkören ";".

PostgreSQL kommer att skapa cross join-produkten med hjälp av ANSI-syntaxen.

SELECT *
FROM persons, places;
id efternamn first_name id plats person_id
1 Dunstan Andrew 1 Dallas (null)
1 Dunstan Andrew 2 London 2
1 Dunstan Andrew 3 Paris 3
1 Dunstan Andrew 4 Madrid (null)
2 Roybal Kirk 1 Dallas (null)
2 Roybal Kirk 2 London 2
2 Roybal Kirk 3 Paris 3
2 Roybal Kirk 4 Madrid (null)
3 Riggs Simon 1 Dallas (null)
3 Riggs Simon 2 London 2
3 Riggs Simon 3 Paris 3
3 Riggs Simon 4 Madrid (null)
6 Wong Markera 1 Dallas (null)
6 Wong Markera 2 London 2
6 Wong Markera 3 Paris 3
6 Wong Markera 4 Madrid (null)

Vilket är mer troligt ett kodningsfel än det avsiktliga resultatet.

För att få den här funktionen avsiktligt rekommenderas det att använda CROSS JOIN uttalande.

SELECT *
FROM persons
CROSS JOIN places;

Detta gör det otvetydigt vad som menades i uttalandet.

NATURLIG JOIN

PostgreSQL stöder NATURAL JOIN syntax, men lite under protest.

SELECT *
FROM persons
NATURAL JOIN places;

Detta ger följande resultat.

id efternamn first_name parent_id plats person_id
1 Dunstan Andrew (null) Dallas (null)
2 Roybal Kirk 1 London 2
3 Riggs Simon 1 Paris 3

Denna syntax är dock ett problem. I vårt exempel har kolumnen "id" i båda tabellerna ingenting med varandra att göra . Denna koppling har gett ett resultat, men ett med helt irrelevant innehåll.

Dessutom kan du ha en fråga som initialt visar det korrekta resultatet, men efterföljande DDL-satser påverkar tyst.

Tänk på:

ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;

Vilken kolumn är nu NATURAL JOIN använder sig av? Alternativen är id, place_id, person_id och alla ovanstående. Jag lämnar svaret som en övning till läsaren.

Denna syntax är en tidsinställd bomb för din kod. Använd det bara inte.

Okej, så du är inte övertygad. Tja, ha åtminstone några förnuftiga kodningskonventioner. För den överordnade tabellen, namnge identitetskolumnen "myparenttable_id". När du refererar till det från underordnade relationer, använd samma namn, "myparenttable_id". Namnge aldrig något "id" och hänvisa aldrig till en kolumn med ett annat namn. Ah, glöm det. Gör bara inte det här.

Du kan bli frestad att göra det tidigare pusslet otydligt genom att använda USING nyckelord. Det skulle se ut så här:

SELECT *
FROM persons
JOIN places
USING (id);

Men USING sökord kan bara dra fördel av exakta namnmatchningar i tabeller. Vilket återigen, i vårt exempel är helt fel.

Det bästa valet för PostgreSQL är att helt enkelt undvika att designa tabeller genom att koda konventionsstandarder.

Sammanfattning

Dessa nyckelordstekniker (mot operatörer) är också tillgängliga på Oracle. De är mer plattformsoberoende och mindre tvetydiga. Bara det skulle göra dem till bästa praxis.

Dessutom avslöjar de logiska fel när de används felaktigt. För all utveckling i PostgreSQL rekommenderar vi ensidigt att du använder explicita sökord.


  1. Skillnaden mellan sys.parameters, sys.system_parameters och sys.all_parameters i SQL Server

  2. Hur sammanfogar man kolumner i en Postgres SELECT?

  3. Kontrollera Oracle RAC Network och IP-information

  4. Vilken SQL-fråga är snabbare? Filtrera på Join-kriterier eller Where-klausul?