4

「in」の代わりに「exists」を使うことを(昨日)学んだばかりです。

 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' )      

つまり、同じエイリアス ( o テーブル othertable ) を使用すると、2 番目の "exist" で最初の exists に問題が発生しますか? それとも完全に独立していますか?

これは Oracle のみに関連するものですか、それともほとんどの RDBMS で有効ですか?

どうもありがとう

4

5 に答える 5

4

これは各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. はい
于 2008-10-09T19:36:03.113 に答える
3

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

最初の IN クエリでは、OtherTable に列 NameID が含まれているかどうか (実際、OtherDesc が Table または OtherTable の列として存在するかどうかにかかわらず、表記は有効です。これはどの例でも明確ではありませんが、おそらく列です)他のテーブルの)。この動作により、相関サブクエリが相関サブクエリになります。それはまた、人々が最初に遭遇したときの日常的な不安の原因でもあります - いつも偶然です. SQL標準では、サブクエリで言及されたテーブルに関連する名前の列がなくても、外側の (メイン) クエリで言及されているテーブル内の関連する名前、

Q1 への答えは「場合による」ですが、もっともらしい仮定 (NameID は両方のテーブルの列として存在し、OtherDesc は OtherTable にのみ存在する) を考えると、結果は返されるデータ セットに関して同じである必要がありますが、そうではない場合があります。性能的には同等。

Q2 への回答は、過去に、不良品ではないにしても劣った DBMS を使用していたということです。EXISTS をサポートしている場合でも、DBMS は結果のカーディナリティについて不平を言う可能性があります。

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

于 2008-10-09T21:20:30.767 に答える
2
  1. Oracle 固有: IN 句を使用してクエリを作成すると、ルールベースのオプティマイザに、内側のクエリで外側のクエリを駆動するように指示することになります。where 句に EXISTS を記述すると、外側のクエリを最初に実行し、各値を使用して内側のクエリから値をフェッチすることをオプティマイザに伝えます。「サブクエリでの IN と EXISTS の違い」を参照してください 。
  2. おそらく。
  3. サブクエリ内で宣言されたエイリアスは、サブクエリ内に存在します。ちなみに、2 つの ANDed サブクエリを使用した例は有効な SQL ではないと思います。AND ではなく UNION のことですか?
于 2008-10-09T19:47:22.343 に答える
1

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

SELECT t.*
FROM yourTable t
    INNER JOIN otherTable ot
        ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
于 2008-10-09T19:36:27.577 に答える