Озоваваме се в третата статия от поредицата за миграция на Oracle. Този път разглеждаме онези странни оператори, които променят критериите за клауза WHERE в Oracle (+). Както всичко останало, PostgreSQL има решение за това.
ДЯСНО ПРИСЪЕДИНЕНЕ
Oracle поддържа и много разработчици използват ANSI външен синтаксис JOIN, използвайки оператори към клаузата за квалификации.
Обикновено това изглежда така:
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
Целта на този синтаксис е дясно външно присъединяване. От гледна точка на теорията на множеството, това е подмножеството, включващо всички места, независимо от лицето.
Резултатът от малка извадка би изглеждал така:
id | фамилно_име | first_name | id | местоположение | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Далас | (NULL) |
2 | Ройбал | Кърк | 2 | Лондон | 2 |
3 | Ригс | Саймън | 3 | Париж | 3 |
Този синтаксис не се поддържа в PostgreSQL.
За да постигнете същия резултат, ще използвате стандартния SQL синтаксис за външни съединения.
SELECT *
FROM persons
RIGHT JOIN places
ON persons.id = places.person_id;
SQL също така предоставя уточняващо наречие OUTER
. Този уточняващ елемент е напълно незадължителен, както всяко RIGHT JOIN
е по дефиниция OUTER
присъединете се.
ПЪЛНО ПРИСЪЕДИНЕНЕ
По същия начин използването на синтаксиса на Oracle за пълно присъединяване не работи в PostgreSQL.
SELECT *
FROM persons, places
WHERE persons.id(+) = places(+);
Целта на този синтаксис е пълен списък с лица и места, независимо дали дадено лице е свързано с място или не.
Резултатът би бил такъв:
id | фамилно_име | first_name** | id | местоположение | person_id |
---|---|---|---|---|---|
1 | (NULL) | (NULL) | 1 | Далас | (NULL) |
2 | Ройбал | Кърк | 2 | Лондон | 2 |
3 | Ригс | Саймън | 3 | Париж | 3 |
4 | Андрю | Дънстан | (NULL) | (NULL) | (NULL) |
Използвайки синтаксиса на PostgreSQL, заявката ще бъде написана по следния начин:
SELECT *
FROM persons
FULL JOIN places
ON persons.id = places.person_id;
Отново OUTER
ключовата дума е напълно незадължителна.
КРЪСТНО ПРИСЪЕДИНЕНЕ
Едно ясно предимство на подхода за използване на ключови думи вместо имплицитни връзки е, че не можете случайно да създадете кръстосани продукти.
Синтаксисът:
SELECT *
FROM persons
LEFT JOIN places;
Ще доведе до грешка:
ERROR: syntax error at or near ";"
Показва, че изявлението не е пълно в завършващия маркер на реда „;“.
PostgreSQL ще създаде продукт за кръстосано свързване, използвайки ANSI синтаксиса.
SELECT *
FROM persons, places;
id | фамилно_име | first_name | id | местоположение | person_id |
---|---|---|---|---|---|
1 | Дънстан | Андрю | 1 | Далас | (нула) |
1 | Дънстан | Андрю | 2 | Лондон | 2 |
1 | Дънстан | Андрю | 3 | Париж | 3 |
1 | Дънстан | Андрю | 4 | Мадрид | (нула) |
2 | Ройбал | Кърк | 1 | Далас | (нула) |
2 | Ройбал | Кърк | 2 | Лондон | 2 |
2 | Ройбал | Кърк | 3 | Париж | 3 |
2 | Ройбал | Кърк | 4 | Мадрид | (нула) |
3 | Ригс | Саймън | 1 | Далас | (нула) |
3 | Ригс | Саймън | 2 | Лондон | 2 |
3 | Ригс | Саймън | 3 | Париж | 3 |
3 | Ригс | Саймън | 4 | Мадрид | (нула) |
6 | Вонг | Марк | 1 | Далас | (нула) |
6 | Вонг | Марк | 2 | Лондон | 2 |
6 | Вонг | Марк | 3 | Париж | 3 |
6 | Вонг | Марк | 4 | Мадрид | (нула) |
Което е по-вероятно грешка в кодирането, отколкото умишлен резултат.
За да получите тази функционалност умишлено, се препоръчва да използвате CROSS JOIN
изявление.
SELECT *
FROM persons
CROSS JOIN places;
По този начин става недвусмислено какво се има предвид в изявлението.
Естествено присъединяване
PostgreSQL поддържа NATURAL JOIN
синтаксис, но малко под протест.
SELECT *
FROM persons
NATURAL JOIN places;
Това дава следния резултат.
id | фамилно_име | first_name | parent_id | местоположение | person_id |
---|---|---|---|---|---|
1 | Дънстан | Андрю | (нула) | Далас | (нула) |
2 | Ройбал | Кърк | 1 | Лондон | 2 |
3 | Ригс | Саймън | 1 | Париж | 3 |
Този синтаксис обаче е проблем. В нашия пример колоната „id“ в двете таблици няма нищо общо помежду си . Това присъединяване даде резултат, но такъв с напълно неподходящо съдържание.
Освен това може да имате заявка, която първоначално представя правилния резултат, но последващите DDL изрази влияят тихо.
Помислете за:
ALTER TABLE person ADD COLUMN places_id bigint;
ALTER TABLE places ADD COLUMN places_id bigint;
ALTER TABLE person ADD COLUMN person_id bigint;
Сега каква колона е NATURAL JOIN
използвайки? Изборите са id, places_id, person_id и всичко по-горе. Ще оставя отговора като упражнение на читателя.
Този синтаксис е бомба със закъснител за вашия код. Просто не го използвайте.
Добре, значи не си убеден. Е, тогава поне имайте някои разумни конвенции за кодиране. За родителската таблица наименувайте колоната за идентичност „myparenttable_id“. Когато препращате към него от връзки с деца, използвайте същото име, „myparenttable_id“. Никога не назовавайте нищо „id“ и никога не правете препратка към колона с различно име. Ах, забрави. Просто не правете това.
Може да се изкушите да разграничите предишния пъзел, като използвате USING
ключова дума. Това би изглеждало така:
SELECT *
FROM persons
JOIN places
USING (id);
Но USING
ключова дума може да се възползва само от точни съвпадения на имена в таблици. Което отново в нашия пример е напълно погрешно.
Най-добрият избор на практика за PostgreSQL е просто да избягвате проектирането на таблици чрез конвенционални стандарти за кодиране.
Резюме
Тези техники за ключови думи (срещу оператори) също са налични в Oracle. Те са по-междуплатформени и по-малко двусмислени. Само това би ги направило най-добрите практики.
В допълнение към това те излагат логически грешки, когато се използват неправилно. За всяка разработка в PostgreSQL едностранно препоръчваме използването на изрични ключови думи.