質問

(昨日)「存在する」を使用することを学んだところです。 " in"の代わりに。

 BAD
 select * from table where nameid in ( 
          select nameid from othertable where otherdesc =  'SomeDesc' )      
 GOOD
 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      

そして、これについていくつか質問があります:

1)私が理解した説明は:"これが優れている理由は、可能な結果の大規模なリストを作成する代わりに、一致する値のみが返されるためです。つまり、最初のサブクエリが900の結果を返す可能性がありますが、2番目のサブクエリは1(yesまたはno)のみを返しますか?

2)過去にRDBMSの苦情がありました:「最初の1000行のみが取得される可能性があります」、この2番目のアプローチはその問題を解決しますか?

3)2番目のサブクエリのエイリアスの範囲は?...エイリアスは括弧内にのみ存在しますか?

たとえば

 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      
 AND 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeOtherDesc' )      

つまり、同じエイリアス(テーブルothertableのo)を使用する場合、2番目の" exist"それは最初の存在に何か問題を提示しますか?または完全に独立していますか?

これはオラクルだけが関係しているのですか、それともほとんどのRDBMSに有効ですか?

どうもありがとう

役に立ちましたか?

解決

各DBMSに固有であり、クエリオプティマイザーに依存します。一部のオプティマイザはIN句を検出して変換します。

テストしたすべてのDBMSで、エイリアスは()内でのみ有効です

ところで、クエリを次のように書き換えることができます:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

そして、あなたの質問に答えるために:

  1. はい
  2. はい
  3. はい

他のヒント

「相関サブクエリ」として知られる複雑な領域に踏み込んでいます。テーブルとキー構造に関する詳細な情報がないため、答えの一部は「多分」しかありません。

最初のINクエリでは、OtherTableに列NameIDが含まれているかどうかにかかわらず、表記法は有効です(実際、OtherDescがTableまたはOtherTableの列として存在するかどうかは、例ではわかりませんが、おそらくOtherTableの列です)。この動作により、相関サブクエリが相関サブクエリになります。それはまた、人々が初めて偶然に遭遇したときの不安の日常的な原因でもあります。 SQL標準では、サブクエリで言及されているテーブルに関連する名前の列がなく、サブクエリの列がある場合、サブクエリの名前を外部クエリの列を参照するように解釈する動作が義務付けられているため、外部(メイン)クエリで言及されているテーブルの関連する名前、SQL標準(のこのビット)への適合を主張したい製品は、異なることをしません。

第1四半期への答えは「依存」ですが、もっともらしい仮定(NameIDが両方のテーブルの列として存在し、OtherDescがOtherTableにのみ存在する)が与えられると、結果は返されるデータセットに関して同じになるはずです。ただし、パフォーマンスの点では同等ではない可能性があります。

第2四半期の答えは、過去には欠陥のあるDBMSではないとしても劣ったものを使用していたということです。 EXISTSをサポートしている場合、DBMSは結果のカーディナリティについてまだ文句を言うかもしれません。

最初のEXISTSクエリに適用されるQ3への回答は、「tはステートメント全体でエイリアスとして使用可能ですが、oは括弧内のエイリアスとしてのみ使用可能」です。 2番目の例のボックスに適用される-2つの副選択を接続し、2番目の副選択(私が見ているときに開いている括弧が欠落している)で、" tはステートメント全体でエイリアスとして利用可能であり、同じテーブルですが、サブクエリごとに「o」というラベルの付いた2つの異なるエイリアスがあります。 OtherDescがOtherTableの特定のNameID値に対して一意である場合、クエリはデータを返さない場合があることに注意してください。それ以外の場合は、同じNameIDを持つOtherTableの2つの行と、そのNameID値を持つTableの各行の2つのOtherDesc値が必要です。

  1. Oracle固有:IN句を使用してクエリを記述する場合、ルールベースのオプティマイザに、内部クエリで外部クエリを駆動することを伝えます。 where句でEXISTSを記述すると、外側のクエリを最初に実行し、各値を使用して内側のクエリから値を取得することをオプティマイザーに伝えます。 " Differenceをご覧ください。サブクエリのINとEXISTSの間。
  2. おそらく。
  3. サブクエリ内で宣言されたエイリアスはサブクエリ内に存在します。ちなみに、ANDされた2つのサブクエリを使用したあなたの例は有効なSQLだとは思いません。 ANDではなくUNIONを意味しましたか?

個人的には、このためにサブクエリではなく、結合を使用します。

SELECT t.*
FROM yourTable t
    INNER JOIN otherTable ot
        ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')

EXISTSが常にINより優れていることを一般化することは困難です。論理的には、その場合、SQLコミュニティはINをEXISTSに置き換えます。 また、INとEXISTSは同じではないことに注意してください。2つを使用すると、結果が異なる場合があります...

INを使用すると、通常、NULLを削除せずに内部テーブルを1回フルテーブルスキャンします(したがって、内部テーブルにNULLがある場合、INはデフォルトでNULLを削除しません)... EXISTSはNULLを削除し、相関サブクエリ、外部クエリからのすべての行に対して内部クエリを実行します。

NULLがなく、単純なクエリ(相関なし)があると仮定すると、検索する行が最後の行でない場合、EXISTのパフォーマンスが向上する可能性があります。最後の行である場合、EXISTSはINなどの最後までスキャンする必要があるかもしれません。

ただし、INとEXISTSは互換性がありません...

scroll top