web-dev-qa-db-ja.com

この内部結合と自然結合の出力の違いを説明する

NATURAL JOINは、結合される2つのテーブルの共通列に基づいて暗黙の結合句を作成するJOIN操作です。 NATURAL JOINは、INNER結合、LEFT OUTER結合、またはRIGHT OUTER結合にすることができます。デフォルトはINNER結合です。 ソース

したがって、両方のテーブルに共通の列がある場合、自然結合は内部結合を実装する簡単な方法になります。

次の表を検討してください。

SELECT * FROM t1;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth 
*/

テーブルをそれ自体に結合します。

SELECT first.id, first.planet FROM t1 first INNER JOIN t1 second ON first.id=second.id;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth   
*/

自然結合表記でも同じことを試してください。

SELECT id, planet FROM t1 NATURAL JOIN t1;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         1 jupiter 
         2 earth   
         2 earth   
*/

ここで自然結合が内部結合を使用して実装されていることを考えると、なぜ複数行なのでしょうか?

更新:

テーブルエイリアスを使用して同じ結合を実行すると、出力が異なります。

SELECT id, planet FROM t1 first NATURAL JOIN t1 second;
/*
        ID PLANET  
---------- --------
         1 jupiter 
         2 earth   
*/
3
Kshitiz Sharma

OracleデータベースはANSI結合構文を内部で理解しません(FULL OUTER JOINを除く)。このようなクエリは、独自の古い結合構文に書き換えられます。たとえば、オプティマイザトレースを有効にすると、次のようになります。

alter session set events '10053 trace name context forever, level 1';

クエリを実行すると、生成されたトレースファイルで、実行されるクエリの最終的な形式を確認できます。

select id, planet from t1 ta natural join t1 tb

に変換されます(BPは私のスキーマです):

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "TB"."ID" "ID","TB"."PLANET" "PLANET" FROM "BP"."T1" "TA","BP"."T1" "TB"
WHERE "TA"."PLANET"="TB"."PLANET" AND "TA"."ID"="TB"."ID"

そして

select id, planet from t1 natural join t1

に変換されます:

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "T1"."ID" "ID","T1"."PLANET" "PLANET" FROM "BP"."T1" "T1","BP"."T1" "T1"
WHERE "T1"."PLANET"="T1"."PLANET" AND "T1"."ID"="T1"."ID"

そして、これが"T1"."PLANET"="T1"."PLANET" AND "T1"."ID"="T1"."ID"の問題です。

しかし、理由を聞かないでください。これは、Oracleにおける「説明できない」ものの1つにすぎません。

変換の結果、同様にあいまいな最終クエリが発生し、トレースファイルに実際のエラーメッセージが表示された場合でも、データベースが誤った結果を返し、クライアントにエラーは返されませんでした。

6
Balazs Papp

バグのようです。

最初に、セルフx NATURAL JOIN xは、元のテーブルと同じ数の行と列を返す必要があります。したがって、2つの行を返す最後のクエリは正しいです。 4行を返す2番目のクエリは、代わりにCROSS JOINを実行しているようです(3行のテーブルで試行すると、9が返されます)。

次に、同じFROM句に同じエイリアスを持つ2つのテーブルを含めることは許可されていないため、クエリは"ORA-00918: column ambiguously defined"エラーまたは類似のエラーを生成するはずです。

dbfiddle.uk のテストを参照してください。クロス結合はこのエラーメッセージを返します。

> SELECT id, planet FROM t1, t1;
> ORA-00918: column ambiguously defined

> SELECT id, planet FROM t1 CROSS JOIN t1;
> ORA-00918: column ambiguously defined

同じクエリ Postgresでテスト済み

> SELECT * FROM t1 NATURAL JOIN t1;
> ERROR:  table name "t1" specified more than once
3
ypercubeᵀᴹ