web-dev-qa-db-ja.com

Oracle IN句でのLIKEの使用

次のように、特定の列に任意の数の値を含むすべての行を返すクエリを作成できることを知っています。

Select * from tbl where my_col in (val1, val2, val3,... valn)

ただし、val1は、たとえば、my_colには、データ型varchar(300)があり、代わりに次のように記述できます。

select * from tbl where my_col LIKE '%val1%'

これらの2つの手法を組み合わせる方法はありますか。列の自由形式のテキストのどこかに表示される可能性がある約30の可能な値を検索する必要があります。

これらの2つのステートメントを次のように組み合わせても機能しないようです。

select * from tbl where my_col LIKE ('%val1%', '%val2%', 'val3%',....) 

select * from tbl where my_col in ('%val1%', '%val2%', 'val3%',....)
16
DeveloperM
select * from tbl 
where my_col like '%val1%' or my_col like'%val2%' or my_col like '%val3%', ...

しかし、それは非常に遅いかもしれないことに注意してください...または、すべての許容値を挿入することもできます(%記号)をテーブルに追加し、そのテーブルを半結合します。

select * from tbl
where exists (select 1 from all_likes where tbl.my_col like all_likes.value)

真の全文検索については、Oracle Textをご覧ください。

http://www.Oracle.com/technetwork/database/enterprise-edition/index-098492.html

28
Lukas Eder

いいえ、これはできません。 IN句の値は完全に一致する必要があります。このように選択を変更できます:

SELECT *
  FROM tbl
 WHERE my_col LIKE %val1%
    OR my_col LIKE %val2%
    OR my_col LIKE %val3%
 ...

Val1、val2、val3 ...が十分に類似している場合、REGEXP_LIKE演算子で正規表現を使用できる場合があります。

6
DCookie

REGEXP_LIKEは、大文字と小文字を区別しない正規表現検索を行います。

select * from Users where Regexp_Like (User_Name, 'karl|anders|leif','i')

これは、フルテーブルスキャンとして実行されます-LIKE or解決策なので、テーブルが小さくない場合、パフォーマンスは実際にになります。あまり使用されない場合は、大丈夫かもしれません。

何らかのパフォーマンスが必要な場合は、Oracle Text(または外部インデクサー)が必要です。

Oracle Textで部分文字列の索引付けを取得するには、CONTEXT索引が必要です。多くのスマートを使用して大きなドキュメントとテキストのインデックスを作成するために作成されているため、少し複雑です。数字やすべての単語(「the」、「an」、「a」、スペースなどを含む)の部分文字列検索など、特定のニーズがある場合は、カスタムレクサーを作成してスマートなものを削除する必要があります...

大量のデータを挿入した場合、特に定期的にではなくトランザクション内で索引を更新する必要がある場合、Oracle Textは処理を高速化しません。

4
KarlP

@Lukas Ederの回答を追加するだけです。

テーブルの作成と値の挿入を回避するための改善(select from dualおよびunpivotは、「オンザフライ」で同じ結果を達成します)。

with all_likes as  
(select * from 
    (select '%val1%' like_1, '%val2%' like_2, '%val3%' like_3, '%val4%' as like_4, '%val5%' as like_5 from dual)
    unpivot (
     united_columns for subquery_column in ("LIKE_1", "LIKE_2", "LIKE_3", "LIKE_4", "LIKE_5"))
  )
    select * from tbl
    where exists (select 1 from all_likes where tbl.my_col like all_likes.united_columns)
1
Plirkee

はい、次のクエリを使用できます。

  SELECT * FROM RandomTable rt 
    WHERE EXISTS (select 1 from table(sys.dbms_debug_vc2coll(//INSERT STRINGS SEPARATED BY COMMA HERE)) as MemoryTable mt where rt.name like mt.column_value);

クエリが受け入れられた回答よりも優れている理由:実行するのにCREATE TABLE権限は必要ありません。これは、SELECT権限だけで実行できます。

1
GabrielBB

これが好き

WHERE CASE WHEN my_col LIKE '%val1%' THEN 1    
           WHEN my_col LIKE '%val2%' THEN 1
           WHEN my_col LIKE '%val3%' THEN 1
           ELSE 0
           END = 1

私はそれが最適だと言っているわけではありませんが、うまくいき、簡単に理解できます。私のクエリのほとんどは一度アドホックに使用されるため、一般にパフォーマンスは問題ではありません。

1
AWOLKiwi

これはかなり速いです:

select * from listofvalue l 
inner join tbl on tbl.mycol like '%' || l.value || '%'
select * from tbl
 where exists (select 1 from all_likes where all_likes.value = substr(tbl.my_col,0, length(tbl.my_col)))
1
Vishnu