web-dev-qa-db-de.com

Verwendung von LIKE in einer Oracle IN-Klausel

Ich weiß, dass ich eine Abfrage schreiben kann, die alle Zeilen zurückgibt, die eine beliebige Anzahl von Werten in einer bestimmten Spalte enthalten.

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

wenn jedoch val1 irgendwo in my_col mit Datentyp varchar (300) vorkommen kann, könnte ich stattdessen Folgendes schreiben:

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

Gibt es eine Möglichkeit, diese beiden Techniken zu kämmen? Ich muss nach etwa 30 möglichen Werten suchen, die an einer beliebigen Stelle im Freiformtext der Spalte stehen können. 

Die Kombination dieser beiden Aussagen auf folgende Weise scheint nicht zu funktionieren:

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

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

Aber Vorsicht, das kann ziemlich langsam sein ... Alternativ können Sie alle akzeptablen Werte (einschließlich %-Zeichen) in eine Tabelle einfügen und diese Tabelle halbzusammenfügen:

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

Für eine echte Volltextsuche möchten Sie möglicherweise Oracle Text betrachten:

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

22
Lukas Eder

Nein, das kannst du nicht. Die Werte in der IN-Klausel müssen exakt übereinstimmen. Sie könnten die Auswahl so ändern:

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

Wenn val1, val2, val3 ... ähnlich genug sind, können Sie reguläre Ausdrücke im REGEXP_LIKE-Operator verwenden.

6
DCookie

Ein REGEXP_LIKE führt eine Regex-Suche nach Groß- und Kleinschreibung durch.

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

Dies wird als full table scan ausgeführt - ebenso wie die LIKE or-Lösung. Die Leistung wird also wirklich schlecht sein, wenn die Tabelle nicht klein ist. Wenn es nicht oft verwendet wird, ist es möglicherweise in Ordnung.

Wenn Sie Leistung benötigen, benötigen Sie Oracle Text (oder einen externen Indexer). 

Für die Indexierung der Teilzeichenfolge mit Oracle Text benötigen Sie einen CONTEXT-Index. Es ist ein bisschen kompliziert, da es für die Indizierung großer Dokumente und Texte mit vielen intelligenten Funktionen erstellt wurde. Wenn Sie besondere Anforderungen haben, wie z. B. Teilzeichenfolgen in Zahlen und allen Wörtern (einschließlich "the" "an" "a", Leerzeichen usw.), müssen Sie benutzerdefinierte Lexer erstellen, um einige intelligente Dinge zu entfernen ...

Wenn Sie viele Daten einfügen, wird Oracle Text nicht schneller, insbesondere wenn der Index innerhalb der Transaktionen und nicht in regelmäßigen Abständen aktualisiert werden muss.

2
KarlP

Nur um @Lukas Eder Antwort hinzuzufügen.

Eine Verbesserung, um das Erstellen von Tabellen und das Einfügen von Werten zu vermeiden (Wir könnten select from dual und unpivot verwenden, um das gleiche Ergebnis "fliegend" zu erzielen): 

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

Ja, Sie können diese Abfrage verwenden:

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

Warum meine Abfrage besser ist als die akzeptierte Antwort: Sie benötigen keine CREATE TABLE-Berechtigung, um sie auszuführen. Dies kann nur mit SELECT-Berechtigungen ausgeführt werden.

1
GabrielBB

Ich bevorzuge das

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

Ich sage nicht, dass es optimal ist, aber es funktioniert und ist leicht zu verstehen. Die meisten meiner Anfragen werden einmal adhoc verwendet, daher ist die Leistung für mich normalerweise kein Problem.

1
AWOLKiwi

Dieser ist ziemlich schnell:

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)))
0
Vishnu