70431


テーブルに保存されている全ての行について、検索条件に該当するか否かを返すSQLについて教えて下さい。例えば5行を含むテーブルに検索を実行した場合、下記のように結果が返ると仮定します（主キーの順で並べます）。検索条件にヒットするものだけ（もしくはヒットしなかったものだけ）取り出せば？、というのは無しです。

> * * *
>
> 1  
>  1  
>  1  
>  0  
>  0

最初はINを使い、下記のように記述していました（検索条件は仮です）。

> SELECT  
>  CASE  
>  WHEN p2.id IN ( SELECT p1.id FROM points p1 WHERE id < 126700 )  
>  THEN 1  
>  ELSE 0  
>  END  
>  FROM  
>  points p2  
>  ORDER BY  
>  p2.id ASC;

しかし検索条件にヒットする件数が一定数以上になると極端に遅くなるのでEXISTSを使い、以下のように書き換えました。

> SELECT  
>  CASE  
>  WHEN EXISTS ( SELECT 1 FROM points p1 WHERE p1.id < 126700 AND p1.id =
> p2.id )  
>  THEN 1  
>  ELSE 0  
>  END  
>  FROM  
>  points p2  
>  ORDER BY  
>  p2.id ASC;

ヒットする件数が少ない場合はINと変わりませんが、EXISTSを使うと極端には遅くならないことがわかりました。いろいろ調べてみるとEXISTSはINNER
JOINで書き換えたほうが良いという情報も見受けられました。ただ私のスキル不足で、上記SQLをINNER
JOINでどのように記述すればよいのかわかりませんでした。  
上記SQLはINNER
JOINで書き換え可能でしょうか。可能な場合、どのようなSQLになりますでしょうか。SQLに詳しい方、お知恵をお貸しください。どうぞよろしくお願いします。


CC BY-SA 4.0
2020-09-16T02:29:46.740
70427
2020-09-16T04:10:36.353
2020-09-16T03:39:16.550
41925
41925
question
sql
EXISTSをINNER JOINで書き換えるには


INはOR条件のようなものなので、1つでも該当レコードが見つかった時点で処理を終了するEXISTSの方が早いのが一般的です。  
今回はidが126700以上のレコードも表示する目的なので、内部結合(INNER JOIN)で目的を達成することは難しいでしょう。  
頑張れば内部結合も使えますが、その場合不自然なSQLになり遅くなると予想されます。

質問のSQLではpointsテーブルを2回使う必要がないので「検索条件にヒットするものだけcase文で取り出せば？」というSQLが自然です。(Postgresqlで下記のSQLの動作を確認)

[code]

    -- ダミーテーブル作成
    with points as
    (select 1 id union all
     select 999999 id)
    -- サンプルSQL
    select case when id < 126700
                then 1
                else 0
           end  id_flag
    from points
    order by id
    
[/code]

どうしても値判別用のテーブルを使うならば左外部結合をする方法もなくはないですが、統計情報は先ほどのSQLよりも遅くなります。  
select文での表示分岐が目的であれば、exists句の使用は正しい方法だと思います。

[code]

    -- ダミーテーブル作成
    with points as
    (select 1 id union all
     select 999999 id)
    -- サンプルSQL
    select case when p2.id is null then 0 else 1 end id_flag
    from points p1
         left outer join points p2
         on p1.id = p2.id
         and p2.id < 126700
    order by p1.id
    
[/code]


CC BY-SA 4.0
2020-09-16T04:10:36.353
70431
2020-09-16T04:10:36.353
9820
70427
answer