it-swarm.com.de

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

In SQL muss ich (leider) oft "LIKE" -Bedingungen verwenden, da Datenbanken gegen nahezu jede Regel der Normalisierung verstoßen. Ich kann das jetzt nicht ändern. Aber das ist für die Frage irrelevant.

Außerdem verwende ich häufig Bedingungen wie WHERE something in (1,1,2,3,5,8,13,21), um die Lesbarkeit und Flexibilität meiner SQL-Anweisungen zu verbessern.

Gibt es eine Möglichkeit, diese beiden Dinge zu kombinieren, ohne komplizierte Unterauswahlen zu schreiben?

Ich möchte etwas so einfaches wie WHERE something LIKE ('bla%', '%foo%', 'batz%') statt dessen:

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

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

280
selfawaresoup

Es gibt keine Kombination aus LIKE & IN in SQL, und noch weniger in TSQL (SQL Server) oder PLSQL (Oracle). Ein Grund 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. Die Syntax unterscheidet sich jedoch immer noch geringfügig:

Orakel:

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

SQL Server:

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

Referenz:

167
OMG Ponies

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

Eine Beispieltabelle:

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  /

Table created.

Die ursprüngliche 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 rows selected.

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 rows selected.

ABER ...

Ich würde es mir aufgrund der nicht so guten Leistung nicht empfehlen. Ich würde bei den verschiedenen LIKE-Prädikaten bleiben. Die Beispiele waren also nur zum Spaß.

55
Rob van Wijk

du bleibst beim 

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

es sei denn, Sie füllen eine temporäre Tabelle aus (schließen Sie die Platzhalter mit den Daten ein) und fügen Sie folgendermaßen hinzu

FROM YourTable                y
    INNER JOIN YourTempTable  t On y.something LIKE t.something

probieren Sie es aus (mit 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)
43
KM.

Bei PostgreSQL gibt es die Form ANY oder ALL:

WHERE col LIKE ANY( subselect )

oder

WHERE col LIKE ALL( subselect )

wo die Unterauswahl genau eine Datenspalte zurückgibt.

18
Benoit

Ich würde vorschlagen, eine TableValue-Benutzerfunktion zu verwenden, wenn Sie die oben gezeigten Inner Join- oder Temp-Table-Techniken kapseln möchten. Dies würde es ermöglichen, etwas klarer zu lesen.

Nach der Verwendung der aufgeteilten Funktion: http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

wir können Folgendes basierend auf einer von mir erstellten Tabelle mit dem Namen "Fish" schreiben (int id, varchar (50) Name).

SELECT Fish.* from Fish 
    JOIN dbo.Split('%ass,%e%',',') as Splits 
    on Name like Splits.items  //items is the name of the output column from the split function.

Ausgänge

 1 Bass 
 2 Pike 
 7 Angler 
 8 Zander 
10
Famous Nerd

Eine andere Lösung sollte in jedem RDBMS funktionieren:

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)
9
mik

Ein Ansatz wäre, die Bedingungen in einer temporären Tabelle (oder Tabellenvariablen in SQL Server) zu speichern und sich wie folgt anzuschließen:

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
7
AdaTheDev

Verwenden Sie stattdessen eine innere Verknüpfung:

SELECT ...
FROM SomeTable
JOIN
(SELECT 'bla%' AS Pattern 
UNION ALL SELECT '%foo%'
UNION ALL SELECT 'batz%'
UNION ALL SELECT 'abc'
) AS Patterns
ON SomeTable.SomeColumn LIKE Patterns.Pattern
7
A-K

sie können dies sogar versuchen

Funktion

CREATE  FUNCTION [dbo].[fn_Split](@text varchar(8000), @delimiter varchar(20))
RETURNS @Strings TABLE
(   
  position int IDENTITY PRIMARY KEY,
  value varchar(8000)  
)
AS
BEGIN

DECLARE @index int
SET @index = -1

WHILE (LEN(@text) > 0)
  BEGIN 
    SET @index = CHARINDEX(@delimiter , @text) 
    IF (@index = 0) AND (LEN(@text) > 0) 
      BEGIN  
        INSERT INTO @Strings VALUES (@text)
          BREAK 
      END 
    IF (@index > 1) 
      BEGIN  
        INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))  
        SET @text = RIGHT(@text, (LEN(@text) - @index)) 
      END 
    ELSE
      SET @text = RIGHT(@text, (LEN(@text) - @index))
    END
  RETURN
END

Abfrage

select * from my_table inner join (select value from fn_split('ABC,MOP',','))
as split_table on my_table.column_name like '%'+split_table.value+'%';

Ich habe eine einfache Lösung, die in postgresql funktioniert, zumindest mit like any gefolgt von der Liste der regulären Ausdrücke. Hier ein Beispiel, in dem einige Antibiotika in einer Liste aufgeführt werden:

select *
from database.table
where lower(drug_name) like any ('{%cillin%,%cyclin%,%xacin%,%mycine%,%cephal%}')
3
mkomo

Ich habe mich auch über so etwas gewundert. Ich habe gerade mit einer Kombination aus SUBSTRING und IN getestet, und es ist eine effektive Lösung für diese Art von Problem. Versuchen Sie die folgende Abfrage:

Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
3
ssah

In Oracle können Sie eine Sammlung auf folgende Weise verwenden:

WHERE EXISTS (SELECT 1
                FROM TABLE(ku$_vcnt('bla%', '%foo%', 'batz%'))
               WHERE something LIKE column_value)

Hier habe ich einen vordefinierten Collection-Typ ku$_vcnt verwendet, aber Sie können Ihren eigenen Typ wie folgt angeben:

CREATE TYPE my_collection AS TABLE OF VARCHAR2(4000);
2
mik

Für SQL Server können Sie auf Dynamic SQL zurückgreifen.

In solchen Situationen haben Sie meistens den Parameter IN-Klausel, der auf Daten aus der Datenbank basiert.

Das folgende Beispiel ist etwas "erzwungen", dies kann jedoch mit verschiedenen realen Fällen in älteren Datenbanken übereinstimmen. 

Angenommen, Sie haben eine Tabelle Persons , in der Personennamen in einem einzigen Feld PersonName als Vorname + '' + Nachname gespeichert sind. Sie müssen alle Personen aus einer Liste von Vornamen auswählen, die im Feld NameToSelect in der Tabelle NamesToSelect gespeichert sind, sowie einige zusätzliche Kriterien (z. B. nach Geschlecht, Geburtsdatum usw.).

Sie können es wie folgt tun

-- @gender is nchar(1), @birthDate is date 

declare 
  @sql nvarchar(MAX),
  @subWhere nvarchar(MAX)
  @params nvarchar(MAX)

-- prepare the where sub-clause to cover LIKE IN (...)
-- it will actually generate where clause PersonName Like 'param1%' or PersonName Like 'param2%' or ...   
set @subWhere = STUFF(
  (
    SELECT ' OR PersonName like ''' + [NameToSelect] + '%''' 
        FROM [NamesToSelect] t FOR XML PATH('')
  ), 1, 4, '')

-- create the dynamic SQL
set @sql ='select 
      PersonName
      ,Gender
      ,BirstDate    -- and other field here         
  from [Persons]
  where 
    Gender = @gender
    AND BirthDate = @birthDate
    AND (' + @subWhere + ')'

set @params = ' @gender nchar(1),
  @birthDate Date'     

EXECUTE sp_executesql @sql, @params,    
  @gender,  
  @birthDate
2
bzamfir

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

Teradata unterstützt LIKE ALL/ANY Syntax:

ALL jeder String in der Liste.
ANY eine beliebige Zeichenfolge in der Liste.

┌──────────────────────────────┬────────────────────────────────────┐
│      THIS expression …       │ IS equivalent to this expression … │
├──────────────────────────────┼────────────────────────────────────┤
│ x LIKE ALL ('A%','%B','%C%') │ x LIKE 'A%'                        │
│                              │ AND x LIKE '%B'                    │
│                              │ AND x LIKE '%C%'                   │
│                              │                                    │
│ x LIKE ANY ('A%','%B','%C%') │ x LIKE 'A%'                        │
│                              │ OR x LIKE '%B'                     │
│                              │ OR x LIKE '%C%'                    │
└──────────────────────────────┴────────────────────────────────────┘
2
Lukasz Szozda

Ich habe möglicherweise eine Lösung dafür, obwohl es meines Wissens nur in SQL Server 2008 funktioniert. Ich habe festgestellt, dass Sie den in https://stackoverflow.com/a/7285095/894974 beschriebenen Zeilenkonstruktor verwenden können, um eine "fiktive" Tabelle mit einer Like-Klausel zu verbinden ..__ Es klingt komplexer ist, schau:

SELECT [name]
  ,[userID]
  ,[name]
  ,[town]
  ,[email]
FROM usr
join (values ('hotmail'),('gmail'),('live')) as myTable(myColumn) on email like '%'+myTable.myColumn+'%' 

Dies führt dazu, dass alle Benutzer mit einer E-Mail-Adresse wie der in der Liste angegebenen Adresse versehen werden. Hoffen Sie, dass sie für jeden von Nutzen ist. Das Problem hatte mich eine Weile gestört.

2
Sander

Dies funktioniert bei durch Kommas getrennten Werten

DECLARE @ARC_CHECKNUM VARCHAR(MAX)
SET @ARC_CHECKNUM = 'ABC,135,MED,ASFSDFSF,AXX'
SELECT ' AND (a.arc_checknum LIKE ''%' + REPLACE(@arc_checknum,',','%'' OR a.arc_checknum LIKE ''%') + '%'')''

Bewertet zu:

 AND (a.arc_checknum LIKE '%ABC%' OR a.arc_checknum LIKE '%135%' OR a.arc_checknum LIKE '%MED%' OR a.arc_checknum LIKE '%ASFSDFSF%' OR a.arc_checknum LIKE '%AXX%')

Wenn Sie Indizes verwenden möchten, müssen Sie das erste '%'-Zeichen weglassen.

1
David F Mayer

In Oracle RBDMS können Sie dieses Verhalten mit der Funktion REGEXP_LIKE erreichen.

Der folgende Code prüft, ob die Zeichenfolge three im Listenausdruck one | two | three vorhanden ist. | vier | fünf (wobei das Pipe-Symbol "|" OR Logikoperation bedeutet). 

SELECT 'Success !!!' result
FROM dual
WHERE REGEXP_LIKE('three', 'one|two|three|four|five');

RESULT
---------------------------------
Success !!!

1 row selected.

Der vorangegangene Ausdruck ist äquivalent zu:

three=one OR three=two OR three=three OR three=four OR three=five

So wird es gelingen.

Der folgende Test schlägt jedoch fehl.

SELECT 'Success !!!' result
FROM dual
WHERE REGEXP_LIKE('ten', 'one|two|three|four|five');

no rows selected

In Oracle stehen seit der 10g-Version mehrere Funktionen für reguläre Ausdrücke (REGEXP_ *) zur Verfügung. Wenn Sie ein Oracle-Entwickler sind und sich für dieses Thema interessieren, sollte dies ein guter Anfang sein Verwenden von regulären Ausdrücken mit Oracle-Datenbank .

1
jackattack

Wenn Sie MySQL verwenden, ist die Volltextsuche am nächsten:

Volltextsuche, MySQL-Dokumentation

1
chris

Keine Antwort wie folgt:

SELECT * FROM table WHERE something LIKE ('bla% %foo% batz%')

In Oracle kein Problem.

0
Hong Van Vit

Vielleicht denkst du die Kombination so:

SELECT  * 
FROM    table t INNER JOIN
(
  SELECT * FROM (VALUES('bla'),('foo'),('batz')) AS list(col)
) l ON t.column  LIKE '%'+l.Col+'%'

Wenn Sie einen Volltextindex für Ihre Zieltabelle definiert haben, können Sie diese Alternative verwenden:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
0
Humayoun_Kabir

Ab 2016 enthält SQL Server eine STRING_SPLITFunktion . Ich verwende SQL Server v17.4 und habe das für mich zum Laufen gebracht:

DECLARE @dashboard nvarchar(50)
SET @dashboard = 'P1%,P7%'

SELECT * from Project p
JOIN STRING_SPLIT(@dashboard, ',') AS sp ON p.ProjectNumber LIKE sp.value
0
Mark

In Teradata können Sie LIKE ANY ('%ABC%','%PQR%','%XYZ%') verwenden. Unten ist ein Beispiel, das für mich zu den gleichen Ergebnissen geführt hat

--===========
--  CHECK ONE
--===========
SELECT *
FROM Random_Table A
WHERE (Lower(A.TRAN_1_DSC) LIKE ('%american%express%centurion%bank%')
OR Lower(A.TRAN_1_DSC) LIKE ('%bofi%federal%bank%')
OR Lower(A.TRAN_1_DSC) LIKE ('%american%express%bank%fsb%'))

;
--===========
--  CHECK TWO
--===========
SELECT *
FROM Random_Table  A
WHERE Lower(A.TRAN_1_DSC) LIKE ANY 
('%american%express%centurion%bank%',
'%bofi%federal%bank%',
'%american%express%bank%fsb%')
0
Piyush Verma