4

私の上司は、私が作成したクエリにバグを発見しました。クエリの結果は上司が正しいことを証明していますが、バグの背後にある理由がわかりません。修正前のクエリ (簡易版) は次のとおりです。

select PTNO,PTNM,CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

そしてここに修正後があります:

select PTNO,PTNM,PARTS.CATCD
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD); 

バグは、列 CATCD に null 値が表示されていたこと、つまり、クエリ結果に PARTS ではなくテーブル CATEGORIES の結果が含まれていたことです。私が理解できないことは次のとおりです。元のクエリにあいまいさがあった場合、Oracle はなぜエラーをスローしなかったのでしょうか。私が理解している限り、左結合の場合、クエリ内の「メイン」テーブル (PARTS) が優先されます。私は間違っていますか、それともこの問題について正しく考えていないだけですか?

アップデート:

あいまいさのエラーがスローされない改訂された例を次に示します。

CREATE TABLE PARTS (PTNO NUMBER, CATCD NUMBER, SECCD NUMBER);

CREATE TABLE CATEGORIES(CATCD NUMBER);

CREATE TABLE SECTIONS(SECCD NUMBER, CATCD NUMBER);


select PTNO,CATCD 
from PARTS 
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD) 
left join SECTIONS on (SECTIONS.SECCD=PARTS.SECCD) ;

誰にも手がかりがありますか?

4

12 に答える 12

6

クエリは次のとおりです(簡易版)

クエリを単純化することで、バグの本当の原因を取り除いたと思います:-)

使用しているオラクルのバージョンは何ですか? Oracle 10g ( 10.2.0.1.0 ) では次のようになります。

create table parts (ptno number , ptnm number , catcd number);  
create table CATEGORIES (catcd number);

select PTNO,PTNM,CATCD from PARTS  
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);

ORA-00918 が表示されます: 列があいまいに定義されています

于 2008-09-12T13:06:24.017 に答える
2

エラーをスローするSQLサーバーに興味があります(そうあるべきです)

select id
from sysobjects s
left join syscolumns c on s.id = c.id

サーバー: メッセージ 209、レベル 16、状態 1、行 1 あいまいな列名 'id'。

select id
from sysobjects 
left join syscolumns  on sysobjects.id = syscolumns.id

サーバー: メッセージ 209、レベル 16、状態 1、行 1 あいまいな列名 'id'。

于 2008-09-12T13:04:42.510 に答える
2

これは、Oracle オプティマイザーのバグである可能性があります。3 つのテーブルを使用したクエリで同じ動作を再現できます。直感的には、エラーが発生するはずです。次のいずれかの方法で書き直すと、エラーが発生します。

(1) 旧形式の外部結合の使用

select ptno, catcd
from parts, categories, sections
where categories.catcd (+) = parts.catcd
  and sections.seccd (+) = parts.seccd

(2) 2 つの結合を明示的に分離する

select ptno, catcd
from (
  select ptno, seccd, catcd
  from parts
  left join categories on (categories.CATCD=parts.CATCD) 
)
left join sections on (sections.SECCD=parts.SECCD)

クエリの実行に関する詳細を取得するために DBMS_XPLAN を使用したところ、興味深い結果が得られました。計画は基本的に、PARTS と CATEGORIES を外部結合し、その結果セットを射影してから、SECTIONS に外部結合することです。興味深い点は、最初の外部結合のプロジェクションでは、PTNO と SECCD のみが含まれていることです。最初の 2 つのテーブルのいずれからの CATCD も含まれていません。したがって、最終結果は 3 番目のテーブルから CATCD を取得します。

しかし、これが原因なのか結果なのかはわかりません。

于 2008-09-15T15:55:35.863 に答える
2

私の経験から、このようなクエリを作成すると、このようなフィールドの重複がある場合、データ結果は結合の左側ではなく右側から CATCD を取得します。

したがって、この結合には PARTS からのすべてのレコードが含まれ、CATEGORIES からの一部のプルスルーのみが含まれるため、右側にデータがない場合は常に CATCD フィールドに NULL が含まれます。

列を PARTS (左側) から明示的に定義することで、フィールドに PARTS のデータがあると仮定して、null 以外の値を取得します。

LEFT JOIN を使用すると、左側のテーブルのフィールドのデータのみが保証されることに注意してください。右側には空の列が存在する可能性があります。

于 2008-09-12T13:29:49.000 に答える
1

Oracle 9.2.0.8.0 を使用しています。「ORA-00918: 列があいまいに定義されています」というエラーが表示されます。

于 2008-09-12T13:17:42.477 に答える
1

残念ながら、例外が発生しない理由を説明することはできませんが、PARTS のバージョンよりも CATEGORIES のバージョンのコラムを選択した理由について推測することはできます。

私が理解している限り、左結合の場合、クエリ(PARTS)の「メイン」テーブルが優先されます

「メイン」とは、単に左結合の左テーブルを意味するのか、クエリを概念的に見ると「駆動」テーブルを意味するのかは明確ではありません...しかし、どちらの場合でも、「メイン」テーブルとして表示されるものあなたが書いたクエリは、必ずしもそのクエリの実際の実行における「メイン」テーブルになるとは限りません。

私の推測では、Oracle は、クエリの実行時に最初にヒットしたテーブルの列を使用しているだけです。また、SQL のほとんどの個々の操作では、1 つのテーブルが他のテーブルより先にヒットする必要がないため、DBMS は解析時に、最初にスキャンする最も効率的なテーブルを決定します。クエリの実行計画を取得してみてください。最初に CATEGORIES にヒットし、次に PARTS にヒットしていることが明らかになるかもしれません。

于 2008-09-12T18:44:39.867 に答える
1

これは、ANSI スタイルの結合を使用する場合の一部の Oracle バージョンの既知のバグです。正しい動作は、ORA-00918 エラーを取得することです。

とにかく、テーブル名を指定するのが常に最善です。そうすれば、別のテーブルでも使用されている名前の新しい列をたまたま追加しても、クエリが壊れることはありません。

于 2008-09-18T15:55:54.230 に答える
0

これはOracle9iのバグです。ANSI表記を使用して3つ以上のテーブルを結合すると、列名のあいまいさは検出されず、エイリアスが使用されていない場合は間違った列が返される可能性があります。

すでに述べたように、10gで修正されているため、エイリアスを使用しない場合はエラーが返されます。

于 2011-08-11T18:23:51.523 に答える
0

あなたが自分自身に尋ねるべきより大きな質問は-なぜ私はカテゴリテーブルに存在しないカテゴリコードをパーツテーブルに持っているのですか?

于 2008-09-17T15:57:10.227 に答える
0

オプティマイザーの作業を少し節約できるため、一般的には具体的ですべての列名を完全に修飾することをお勧めします。確かにSQL Serverで。

Oracle docsから収集できることから、選択リストで列名を2回選択するか、選択リストで1回選択してから、order by句のように別の場所で再度選択した場合にのみスローされるようです。

おそらく、「文書化されていない機能」を発見した可能性があります:)

于 2008-09-12T13:00:56.993 に答える
0

HollyStyles のように、Oracle のドキュメントには、あなたが見ているものを説明できるものは何も見つかりません。

PostgreSQL、DB2、MySQL、および MSSQL はすべて、あいまいであるため、最初のクエリの実行を拒否します。

于 2008-09-12T13:19:12.240 に答える
0

@Pat: クエリに対して同じエラーが発生します。私のクエリは、最初に投稿したものよりも少し複雑です。現在、再現可能な簡単な例に取り組んでいます。

于 2008-09-12T13:42:18.580 に答える