Oracle移行シリーズの3番目の記事をご覧ください。今回は、Oracle(+)のWHERE句の基準を変更する奇妙な演算子を見ていきます。他のすべてと同様に、PostgreSQLにはそのためのソリューションがあります。
Oracleは、修飾句の演算子を使用したANSI外部JOIN構文をサポートしており、多くの開発者が使用しています。
通常、これは次のようになります。
SELECT *
FROM person, places
WHERE person.id = places.person_id(+)
この構文の目的は、右外部結合です。集合論の用語では、これは人に関係なく、すべての場所を含むサブセットです。
小さなサンプルの結果は次のようになります:
id | last_name | 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 | last_name | 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
キーワードは完全にオプションです。
CROSS JOIN
暗黙の関係ではなくキーワードを使用するアプローチの明確な利点の1つは、誤って外積を作成できないことです。
構文:
SELECT *
FROM persons
LEFT JOIN places;
エラーが発生します:
ERROR: syntax error at or near ";"
行末マーカー「;」でステートメントが完了していないことを示します。
PostgreSQLは、ANSI構文を使用して相互結合製品を作成します。
SELECT *
FROM persons, places;
id | last_name | first_name | id | 場所 | person_id |
---|---|---|---|---|---|
1 | ダンスタン | アンドリュー | 1 | ダラス | (null) |
1 | ダンスタン | アンドリュー | 2 | ロンドン | 2 |
1 | ダンスタン | アンドリュー | 3 | パリ | 3 |
1 | ダンスタン | アンドリュー | 4 | マドリード | (null) |
2 | ロイヤル | カーク | 1 | ダラス | (null) |
2 | ロイヤル | カーク | 2 | ロンドン | 2 |
2 | ロイヤル | カーク | 3 | パリ | 3 |
2 | ロイヤル | カーク | 4 | マドリード | (null) |
3 | リグ | サイモン | 1 | ダラス | (null) |
3 | リグ | サイモン | 2 | ロンドン | 2 |
3 | リグ | サイモン | 3 | パリ | 3 |
3 | リグ | サイモン | 4 | マドリード | (null) |
6 | ウォン | マーク | 1 | ダラス | (null) |
6 | ウォン | マーク | 2 | ロンドン | 2 |
6 | ウォン | マーク | 3 | パリ | 3 |
6 | ウォン | マーク | 4 | マドリード | (null) |
これは、意図的な結果よりもコーディングエラーである可能性が高いです。
この機能を意図的に取得するには、CROSS JOIN
を使用することをお勧めします。 ステートメント。
SELECT *
FROM persons
CROSS JOIN places;
したがって、ステートメントの意味が明確になります。
NATURAL JOIN
PostgreSQLはNATURAL JOIN
をサポートしています 構文ですが、少し抗議しています。
SELECT *
FROM persons
NATURAL JOIN places;
これにより、次の結果が生成されます。
id | last_name | first_name | parent_id | 場所 | person_id |
---|---|---|---|---|---|
1 | ダンスタン | アンドリュー | (null) | ダラス | (null) |
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、および上記のすべてです。答えは読者の練習問題として残しておきます。
この構文は、コードにとって時限爆弾です。使用しないでください。
わかりました、それであなたは確信していません。それなら、少なくともいくつかの正しいコーディング規則があります。親テーブルの場合、ID列に「myparenttable_id」という名前を付けます。子関係から参照する場合は、同じ名前「myparenttable_id」を使用してください。 「id」という名前を付けたり、別の名前の列を参照したりしないでください。ああ、忘れて。これはしないでください。
USING
を使用して、前のパズルの曖昧さを解消したくなるかもしれません。 キーワード。これは次のようになります:
SELECT *
FROM persons
JOIN places
USING (id);
しかし、USING
キーワードは、テーブル間での完全な名前の一致のみを利用できます。繰り返しになりますが、この例ではまったく間違っています。
PostgreSQLのベストプラクティスの選択は、規約標準をコーディングしてテーブルを設計することを単に避けることです。
これらのキーワード手法(対演算子)は、Oracleでも利用できます。それらはよりクロスプラットフォームであり、曖昧さが少なくなっています。それだけでベストプラクティスになります。
それに加えて、不適切に使用すると論理エラーが発生します。 PostgreSQLでの開発では、一方的に明示的なキーワードを使用することをお勧めします。