452 Stimmen

Gibt es eine Kombination von "LIKE" und "IN" in SQL?

In SQL muss ich (leider) oft "LIKE"-Bedingungen verwenden, aufgrund von Datenbanken, die nahezu alle Regeln der Normalisierung verletzen. Das kann ich im Moment nicht ändern. Aber das ist irrelevant für die Frage.

Weiterhin verwende ich oft Bedingungen wie WHERE etwas in (1,1,2,3,5,8,13,21) für bessere Lesbarkeit und Flexibilität meiner SQL-Anweisungen.

Gibt es eine mögliche Möglichkeit, diese beiden Dinge ohne das Schreiben von komplizierten Unterabfragen zu kombinieren?

Ich möchte etwas so Einfaches wie WHERE etwas LIKE ('bla%', '%foo%', 'batz%') anstelle von diesem:

WHERE something LIKE 'bla%'
OR something LIKE '%foo%'
OR something LIKE 'batz%'

Ich arbeite hier mit SQL Server und Oracle, aber ich bin interessiert, ob dies überhaupt in einem RDBMS möglich ist.

1 Stimmen

Du musst tun und mögen oder: UND (etwas WIE '%Ding%' oder etwas WIE '%Ding%' oder etwas WIE '%Ding%')

1 Stimmen

Ich wünschte, wir hätten Teradatas like any / like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-al‌​l. (Zur Erinnerung, dies wurde im Oracle Community Ideas-Forum angefordert community.oracle.com/ideas/11592)

0 Stimmen

245voto

OMG Ponies Punkte 312816

Es gibt keine Kombination von LIKE & IN in SQL, schon gar nicht in TSQL (SQL Server) oder PLSQL (Oracle). Ein Teil des Grundes dafür ist, dass die Volltextsuche (FTS) die empfohlene Alternative ist.

Sowohl Oracle als auch SQL Server FTS-Implementierungen unterstützen das Schlüsselwort CONTAINS, aber die Syntax ist immer noch leicht unterschiedlich:

Oracle:

WHERE CONTAINS(t.something, 'bla OR foo OR batz', 1) > 0

SQL Server:

WHERE CONTAINS(t.something, '"bla*" OR "foo*" OR "batz*"')

Die Spalte, die Sie abfragen, muss volltextindiziert sein.

Referenz:

13 Stimmen

Hi, mit Oracle musst du Plaintext-Indizes auf den Spalten erstellen, auf die du den "CONTAINS"-Operator anwenden möchtest. Abhängig von deinem Datenvolumen könnte dies recht lange dauern.

21 Stimmen

Mit SQL Server (mindestens in der Version 2008) trifft auch der Kommentar von @Pilooz zu, Sie müssen Volltextindizes erstellen.

0 Stimmen

Die maximale Länge beträgt 4000.

76voto

Rob van Wijk Punkte 17434

Wenn Sie Ihre Aussage leicht lesbar machen möchten, können Sie REGEXP_LIKE verwenden (verfügbar ab Oracle-Version 10).

Ein Beispiel für eine Tabelle:

SQL> create table mytable (something)
  2  as
  3  select 'blabla' from dual union all
  4  select 'notbla' from dual union all
  5  select 'ofooof' from dual union all
  6  select 'ofofof' from dual union all
  7  select 'batzzz' from dual
  8  /

Tabelle erstellt.

Die originale Syntax:

SQL> select something
  2    from mytable
  3   where something like 'bla%'
  4      or something like '%foo%'
  5      or something like 'batz%'
  6  /

SOMETH
------
blabla
ofooof
batzzz

3 Zeilen ausgewählt.

Und eine einfach aussehende Abfrage mit REGEXP_LIKE

SQL> select something
  2    from mytable
  3   where regexp_like (something,'^bla|foo|^batz')
  4  /

SOMETH
------
blabla
ofooof
batzzz

3 Zeilen ausgewählt.

ABER ...

Ich würde es aufgrund der nicht besonders guten Leistung nicht empfehlen. Ich würde bei mehreren LIKE-Prädikaten bleiben. Also waren die Beispiele nur zum Spaß.

4 Stimmen

+1 gute Illustration der REGEXP-Nutzung in 10g. Ich frage mich jedoch, ob die Leistung wirklich so viel schlechter wäre. Beide werden vollständige Tabellen- und/oder Indexscans erfordern, oder?

14 Stimmen

Wahr. Aber reguläre Ausdrücke belasten die CPU wie verrückt, nicht das I/O. Ob es schlimmer ist und wie viel schlimmer es ist, hängt davon ab, wie groß Ihre Liste von Ausdrücken ist und ob die Spalte indiziert ist oder nicht, unter anderem. Es handelt sich nur um eine Warnung, damit der ursprüngliche Verfasser nicht überrascht ist, wenn er mit der Implementierung beginnt.

66voto

KM. Punkte 98297

Sie sind stecken geblieben mit dem

WHERE something LIKE 'bla%'
OR something LIKE '%foo%'
OR something LIKE 'batz%'

es sei denn, Sie füllen eine Temporäre Tabelle (inklusive der Wildcards mit den Daten) und verbinden es auf diese Weise:

FROM IhreTabelle                y
    INNER JOIN IhreTemporäreTabelle  t On y.something LIKE t.something

Probieren Sie es aus (verwenden Sie die SQL Server Syntax):

declare @x table (x varchar(10))
declare @y table (y varchar(10))

insert @x values ('abcdefg')
insert @x values ('abc')
insert @x values ('mnop')

insert @y values ('%abc%')
insert @y values ('%b%')

select distinct *
FROM @x x
WHERE x.x LIKE '%abc%' 
   or x.x LIKE '%b%'

select distinct x.*  
FROM @x             x
    INNER JOIN  @y  y On x.x LIKE y.y

AUSGABE:

x
----------
abcdefg
abc

(2 row(s) affected)

x
----------
abc
abcdefg

(2 row(s) affected)

0 Stimmen

Ok, das würde funktionieren, aber es geht nicht in die von mir beabsichtigte Richtung, den SQL-Befehl leichter lesbar zu machen :)

11 Stimmen

Im SQL gehen Sie auf Indexnutzung und Leistung. Verwenden Sie nur Einrückung und Benennung für die SQL-Lesbarkeit. Wenn Sie andere Änderungen nur zur Lesbarkeit vornehmen, riskieren Sie eine Änderung des Ausführungsplans (der die Indexnutzung und Leistung beeinflusst). Wenn Sie nicht vorsichtig sind, können Sie durch unbedeutende Änderungen eine sofort laufende Abfrage leicht in eine sehr langsame umwandeln.

0 Stimmen

Die erste Aussage dieser Antwort ist entscheidend - die meisten SQL-basierten Systeme und Sprachen unterstützen nicht, was Sie wollen, zumindest nicht ohne Implementierung von Umgehungen. (Würde in SQL Server eine Volltextindizierung helfen?)

26voto

Benoit Punkte 72929

Mit PostgreSQL gibt es die ANY oder ALL Form:

WHERE col LIKE ANY( subselect )

oder

WHERE col LIKE ALL( subselect )

wo die subselect genau eine Datenspalte zurückgibt.

1 Stimmen

Sind LIKE ANY und LIKE ALL in allen SQL-Dialekten üblich, d.h. Teil der Kerndialektik oder spezifisch für einen Dialekt?

1 Stimmen

@AssadEbrahim, nein, sie sind spezifisch. Oracle hat = ANY oder <> ALL, aber es funktioniert nur in SQL, nicht zum Beispiel in PLSQL.

0 Stimmen

Ich glaube, dies ist die Standard-Syntax (aber nicht viele Datenbankmanagementsysteme haben sie implementiert)

20voto

mik Punkte 3076

Eine weitere Lösung, die auf allen RDBMS funktionieren sollte:

WHERE EXISTS (SELECT 1
                FROM (SELECT 'bla%' pattern FROM dual UNION ALL
                      SELECT '%foo%'        FROM dual UNION ALL
                      SELECT 'batz%'        FROM dual)
               WHERE something LIKE pattern)

Das innere SELECT kann durch eine andere Quelle von Mustern wie einer Tabelle (oder einer Ansicht) ersetzt werden, auf diese Weise:

WHERE EXISTS (SELECT 1
                FROM table_of_patterns t
               WHERE something LIKE t.pattern)

table_of_patterns sollte mindestens eine Spalte pattern enthalten und kann wie folgt befüllt werden:

INSERT INTO table_of_patterns(pattern) VALUES ('bla%');
INSERT INTO table_of_patterns(pattern) VALUES ('%foo%');
INSERT INTO table_of_patterns(pattern) VALUES ('batz%');

1 Stimmen

Aber es ist hässlicher als eine Reihe von ODER-Anweisungen

3 Stimmen

@Fandango68, aber die Vereinigung der Selects kann durch eine andere Quelle von Mustern wie eine Tabelle, eine Ansicht, etc. ersetzt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X