Ocitáme se u třetího článku série migrace Oracle. Tentokrát se podíváme na ty podivné operátory, které upravují kritéria klauzule WHERE v Oracle (+). Jako všechno ostatní, i na to má PostgreSQL řešení.
SPRÁVNÉ PŘIPOJENÍ
Oracle podporuje a mnoho vývojářů používá vnější syntaxi ANSI JOIN pomocí operátorů v kvalifikační klauzuli.
Obvykle to vypadá nějak takto:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
Cílem této syntaxe je pravé vnější spojení. Z hlediska teorie množin je to podmnožina zahrnující všechna místa bez ohledu na osobu.
Výsledek malého vzorku by vypadal takto:
id | příjmení | křestní_jméno | id | umístění | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | Londýn | 2 |
3 | Riggs | Simon | 3 | Paříž | 3 |
Tato syntaxe není v PostgreSQL podporována.
K dosažení stejného výsledku byste použili standardní syntaxi SQL pro vnější spojení.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL také poskytuje objasňující příslovce OUTER
. Tento objasňovač je zcela volitelný, stejně jako jakékoli RIGHT JOIN
je z definice OUTER
připojte se.
PLNÉ PŘIPOJENÍ
Podobně použití syntaxe Oracle pro úplné spojení nefunguje v PostgreSQL.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
Cílem této syntaxe je úplný seznam osob a míst bez ohledu na to, zda je osoba s místem spojena nebo ne.
Výsledek by vypadal takto:
id | příjmení | křestní_jméno** | id | umístění | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Dallas | (NULL) |
2 | Roybal | Kirk | 2 | Londýn | 2 |
3 | Riggs | Simon | 3 | Paříž | 3 |
4 | Andrew | Dunstan | (NULL) | (NULL) | (NULL) |
Pomocí syntaxe PostgreSQL by byl dotaz napsán takto:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
Opět OUTER
klíčové slovo je zcela nepovinné.
CROSS JOIN
Jednou výraznou výhodou přístupu k používání klíčových slov namísto implicitních vztahů je to, že nemůžete náhodně vytvořit křížový produkt.
Syntaxe:
SELECT *
FROM persons
LEFT JOIN places;
Výsledkem bude chyba:
ERROR: syntax error at or near ";"
Indikuje, že příkaz není úplný na značce konce řádku „;“.
PostgreSQL vytvoří produkt křížového spojení pomocí syntaxe ANSI.
SELECT *
FROM persons, places;
id | last_name | first_name | id | místo | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrej | 1 | Dallas | (null) |
1 | Dunstan | Andrew | 2 | Londýn | 2 |
1 | Dunstan | Andrew | 3 | Paříž | 3 |
1 | Dunstan | Andrej | 4 | Madrid | (null) |
2 | Roybal | Kirk | 1 | Dallas | (null) |
2 | Roybal | Kirk | 2 | Londýn | 2 |
2 | Roybal | Kirk | 3 | Paříž | 3 |
2 | Roybal | Kirk | 4 | Madrid | (null) |
3 | Riggs | Simon | 1 | Dallas | (null) |
3 | Riggs | Simon | 2 | Londýn | 2 |
3 | Riggs | Simon | 3 | Paříž | 3 |
3 | Riggs | Simon | 4 | Madrid | (null) |
6 | Wong | Označit | 1 | Dallas | (null) |
6 | Wong | Označit | 2 | Londýn | 2 |
6 | Wong | Označit | 3 | Paříž | 3 |
6 | Wong | Označit | 4 | Madrid | (null) |
Což je pravděpodobnější chyba v kódování než záměrný výsledek.
Chcete-li tuto funkci získat záměrně, doporučujeme použít CROSS JOIN
prohlášení.
SELECT *
FROM persons
CROSS JOIN places;
Tím je jednoznačné, co bylo v prohlášení myšleno.
NATURAL JOIN
PostgreSQL podporuje NATURAL JOIN
syntaxe, ale trochu pod protestem.
SELECT *
FROM persons
NATURAL JOIN places;
Výsledkem je následující.
id | last_name | first_name | parent_id | místo | person_id |
---|---|---|---|---|---|
1 | Dunstan | Andrew | (null) | Dallas | (null) |
2 | Roybal | Kirk | 1 | Londýn | 2 |
3 | Riggs | Simon | 1 | Paříž | 3 |
Tato syntaxe je však problém. V našem příkladu sloupec „id“ v obou tabulkách nemá nic společného . Toto spojení přineslo výsledek, ale se zcela irelevantním obsahem.
Navíc můžete mít dotaz, který zpočátku prezentuje správný výsledek, ale následné příkazy DDL tiše ovlivní.
Zvažte:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Nyní, který sloupec je NATURAL JOIN
použitím? Možnosti jsou id, places_id, person_id a všechny výše uvedené. Odpověď nechám jako cvičení na čtenáři.
Tato syntaxe je pro váš kód časovanou bombou. Prostě to nepoužívejte.
Dobře, takže nejste přesvědčeni. No, pak alespoň mějte nějaké rozumné kódovací konvence. Pro nadřazenou tabulku pojmenujte sloupec identity „myparenttable_id“. Když na něj odkazujete z podřízených vztahů, použijte stejný název, „myparenttable_id“. Nikdy nic nepojmenujte „id“ a nikdy neodkazujte na sloupec s jiným názvem. Zapomeň na to. Prostě to nedělej.
Můžete být v pokušení rozdělit předchozí hádanku pomocí USING
klíčové slovo. To by vypadalo takto:
SELECT *
FROM persons
JOIN places
USING (id);
Ale USING
klíčové slovo může využívat pouze přesné shody názvů napříč tabulkami. Což je opět v našem příkladu naprosto špatné.
Nejlepší volbou pro PostgreSQL je jednoduše se vyhnout navrhování tabulek pomocí standardů konvence kódování.
Přehled
Tyto techniky klíčových slov (vs. operátory) jsou také dostupné na Oracle. Jsou více multiplatformní a méně nejednoznačné. To samo o sobě by z nich udělalo osvědčené postupy.
Navíc při nesprávném použití odhalují logické chyby. Pro jakýkoli vývoj v PostgreSQL jednostranně doporučujeme používat explicitní klíčová slova.