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

340

In SQL muss ich (leider) häufig " LIKE" Bedingungen verwenden, da Datenbanken gegen fast jede Normalisierungsregel verstoßen. Das kann ich momentan 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)für eine bessere Lesbarkeit und Flexibilität meiner SQL-Anweisungen.

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%')stattdessen:

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.

selfawaresoup
quelle
1
Sie müssen tun und mögen oder: UND (etwas wie '% thing%' oder etwas wie '% thing%' oder etwas wie '% thing%')
Cosmic Hawk
Ich wünschte, wir hätten Teradatas like any/ like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-all . (Für die Aufzeichnung wurde dies im Oracle Community Ideas Forum community.oracle.com/ideas/11592 angefordert )
William Robertson
ähnliche stackoverflow.com/q/1076097/125981
Mark Schultheiss

Antworten:

196

Es gibt keine Kombination von LIKE & IN in SQL, geschweige denn 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 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*"')

Die Spalte, die Sie abfragen, muss im Volltext indiziert sein.

Referenz:

OMG Ponys
quelle
11
Hallo, mit Oracle müssen Sie Klartextindizes für die Spalten erstellen, auf die Sie den Operator "CONTAINS" anwenden möchten. Abhängig von Ihrem Datenvolumen kann dies sehr lang sein.
Pierre-Gilles Levallois
18
Bei SQL Server (mindestens der Version 2008) gilt auch der Kommentar von @Pilooz. Sie müssen Volltextindizes erstellen.
Marcel
Die maximale Länge beträgt 4000.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
59

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

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 selbst nicht empfehlen, da die Leistung nicht so gut ist. Ich würde mich an die verschiedenen LIKE-Prädikate halten. Die Beispiele waren also nur zum Spaß.

Rob van Wijk
quelle
4
+1 schönes Beispiel für die Verwendung von REGEXP in 10g. Ich bin allerdings gespannt, ob die Leistung wirklich viel schlechter wäre. Für beide sind vollständige Tabellen- und / oder Index-Scans erforderlich, nicht wahr?
DCookie
12
Wahr. Aber reguläre Ausdrücke brennen die CPU wie verrückt, nicht die E / A. Ob es schlimmer ist und wie viel schlimmer es ist, hängt unter anderem davon ab, wie groß Ihre Liste von Ausdrücken ist und ob die Spalte indiziert ist oder nicht. Es ist nur eine Warnung, damit das Originalplakat nicht überrascht ist, wenn er mit der Implementierung beginnt.
Rob van Wijk
49

du steckst mit dem fest

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

es sei denn, Sie füllen eine temporäre Tabelle (fügen Sie die Platzhalter in die Daten ein) und treten wie folgt bei:

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)
KM.
quelle
Ok, das würde funktionieren, aber es geht nicht in meine beabsichtigte Richtung, die SQL-Anweisung leichter lesbar zu machen :)
selfawaresoup
10
In SQL setzen Sie auf Indexnutzung und Leistung. Verwenden Sie Einrücken und Benennen nur für die SQL-Lesbarkeit. Wenn Sie andere Änderungen nur für die Lesbarkeit vornehmen, besteht die Gefahr, dass Sie den Ausführungsplan ändern (was sich auf die Indexnutzung und -leistung auswirkt). Wenn Sie nicht vorsichtig sind, können Sie eine sofort ausgeführte Abfrage leicht in eine sehr langsame ändern, indem Sie geringfügige Änderungen vornehmen.
KM.
Die erste Aussage dieser Antwort ist der Schlüssel - (die meisten?) SQL-basierte Systeme und Sprachen unterstützen nicht das, was Sie wollen, nicht ohne die Implementierung von Workarounds. (In SQL Server würde die Volltextindizierung helfen?)
Philip Kelley
@Philip Kelley, kann die SQL Server-Volltextindizierung dies LIKE 'bla%' im Beispielcode des OP tun ? oder kann man nur LIKE '%bla%'suchen?
KM.
Ich weiß es ehrlich gesagt nicht, ich habe noch nie die FT-Indizierung verwendet. Ich warf es als Beispiel für eine mögliche Problemumgehung ein, die bereits im Produkt enthalten ist. Für das, was er tut (A oder B oder C), vermute ich, dass es nicht funktioniert, bin ziemlich zuversichtlich, dass es viel Mühe kosten würde, dies festzustellen, und weiß, dass es außerhalb des Rahmens seiner ursprünglichen Frage liegt (tut) SQL macht es nativ).
Philip Kelley
20

Bei PostgreSQL gibt es die Form ANYoder ALL:

WHERE col LIKE ANY( subselect )

oder

WHERE col LIKE ALL( subselect )

Dabei gibt die Unterauswahl genau eine Datenspalte zurück.

Benoit
quelle
1
Sind LIKE ANYund LIKE ALLsind alle SQL-Dialekte gemeinsam, dh Teil der Kernsprache, oder spezifisch für einen Dialekt?
Assad Ebrahim
1
@AssadEbrahim, nein, sie sind spezifisch. Oracle hat = ANYoder <> ALLfunktioniert aber nur in SQL, nicht beispielsweise in PLSQL.
Benoit
Ich denke, dies ist die Standardsyntax (aber nicht viele DBMS haben sie implementiert)
ypercubeᵀᴹ
Für Postgres siehe stackoverflow.com/questions/2245536/…
Rogerdpack
13

Eine andere Lösung sollte auf 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)
mik
quelle
1
Aber es ist hässlicher als eine Reihe von OR-Anweisungen
Fandango68
1
@ Fandango68, aber die Vereinigung von Auswahlen kann durch eine andere Quelle von Mustern wie eine Tabelle, eine Ansicht usw. ersetzt werden
mik
10

Ich würde vorschlagen, eine TableValue-Benutzerfunktion zu verwenden, wenn Sie die oben gezeigten Techniken für innere Verknüpfungen oder temporäre Tabellen kapseln möchten. Dies würde es ermöglichen, etwas klarer zu lesen.

Nach Verwendung der Split-Funktion, die unter http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx definiert ist

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 Hecht
7 Angler
8 Zander
Berühmter Nerd
quelle
1
Eine Zeile wird dupliziert, wenn viele Bedingungen gleichzeitig übereinstimmen.
Mik
7

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

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
AdaTheDev
quelle
Eine Zeile wird dupliziert, wenn viele Bedingungen gleichzeitig übereinstimmen.
Mik
7

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
AK
quelle
1
Genau das möchte ich vermeiden. Obwohl es funktioniert.
Selfawaresoup
Warum diese Lösung vermeiden? Es funktioniert so schnell wie die akzeptierte Lösung und ist ebenso vielseitig.
Phil Factor
3
@PhilFactor Diese Lösung kann doppelte Zeilen erstellen.
Jakub Kania
5

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

Teradata unterstützt die LIKE ALL / ANY- Syntax:

ALLE Zeichenfolge in der Liste.
JEDE 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%'                    
└──────────────────────────────┴────────────────────────────────────┘

BEARBEITEN:

jOOQ Version 3.12.0 unterstützt diese Syntax:

Fügen Sie synthetische Operatoren [NOT] LIKE ANY und [NOT] LIKE ALL hinzu

Häufig möchten SQL-Benutzer LIKE- und IN-Prädikate kombinieren können, wie in:

SELECT *
FROM customer
WHERE last_name [ NOT ] LIKE ANY ('A%', 'E%') [ ESCAPE '!' ]

Die Problemumgehung besteht darin, das Prädikat manuell auf das Äquivalent zu erweitern

SELECT *
FROM customer
WHERE last_name LIKE 'A%'
OR last_name LIKE 'E%'

jOOQ könnte ein solches synthetisches Prädikat sofort unterstützen.


PostgreSQL LIKE/ILIKE ANY (ARRAY[]):

SELECT *
FROM t
WHERE c LIKE ANY (ARRAY['A%', '%B']);

SELECT *
FROM t
WHERE c LIKE ANY ('{"Do%", "%at"}');

db <> Geigen-Demo


Snowflake unterstützt auch LIKE ANY / LIKE ALL Matching:

WIE JEDER / ALLE

Ermöglicht die Groß- und Kleinschreibung von Zeichenfolgen basierend auf dem Vergleich mit einem oder mehreren Mustern.

<subject> LIKE ANY (<pattern1> [, <pattern2> ... ] ) [ ESCAPE <escape_char> ]

Beispiel:

SELECT * 
FROM like_example 
WHERE subject LIKE ANY ('%Jo%oe%','T%e')
-- WHERE subject LIKE ALL ('%Jo%oe%','J%e')
Lukasz Szozda
quelle
4

Du kannst es 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+'%';
SimarjeetSingh Panghlia
quelle
4

Ich habe eine einfache Lösung, die zumindest in postgresql funktioniert , like anygefolgt von der Liste der regulären Ausdrücke . Hier ist ein Beispiel für die Identifizierung einiger Antibiotika in einer Liste:

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

Ich habe mich auch nach so etwas gefragt. Ich habe gerade mit einer Kombination von SUBSTRINGund getestet INund 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')
ssah
quelle
1
Ein Problem bei diesem Ansatz ist, dass Sie nicht mehr in der Lage sind, einen Index für etwas zu verwenden, falls vorhanden.
ShoeLace
1
Dies wird nie 'batz' finden
mik
3

In Oracle können Sie eine Sammlung folgendermaßen verwenden:

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

Hier habe ich einen vordefinierten Sammlungstyp verwendet ku$_vcnt, aber Sie können Ihren eigenen wie folgt deklarieren:

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

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

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

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

Angenommen, Sie haben eine Tabelle Personen, in der Personennamen in einem einzelnen Feld Personenname 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 (wie nach Geschlecht, Geburtsdatum usw. gefiltert).

Sie können dies 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
bzamfir
quelle
2

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

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 eine E-Mail-Adresse haben, wie sie in der Liste angegeben ist. Hoffe, es ist für jeden von Nutzen. Das Problem hatte mich eine Weile beschäftigt.

Sander
quelle
1
Das ist interessant. Beachten Sie jedoch, dass dies nur für eine kleine Tabelle verwendet werden sollte, da die like-Anweisung keine Indizes verwenden kann. Aus diesem Grund ist die Volltextsuche zwar schwieriger einzurichten, aber die bessere Wahl, wenn Sie über viele Daten verfügen.
HLGEM
2

Ab 2016 enthält SQL Server eine STRING_SPLIT Funktion . Ich verwende SQL Server v17.4 und habe Folgendes für mich:

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

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

Dies funktioniert für durch Kommas getrennte Werte

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 möchten, dass Indizes verwendet werden, müssen Sie das erste '%'Zeichen weglassen .

David F. Mayer
quelle
1

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

Der folgende Code testet, ob die Zeichenfolge drei im Listenausdruck eins | vorhanden ist zwei | drei | vier | fünf (wobei das Pipe- Symbol " | " ODER-Verknüpfung bedeutet).

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

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

1 row selected.

Der vorangegangene Ausdruck entspricht:

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

So wird es gelingen.

Auf der anderen Seite schlägt der folgende Test fehl.

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

no rows selected

In Oracle sind seit der 10g-Version verschiedene Funktionen für reguläre Ausdrücke (REGEXP_ *) verfügbar. Wenn Sie ein Oracle-Entwickler sind und sich für dieses Thema interessieren, sollte dies ein guter Anfang für die Verwendung regulärer Ausdrücke mit Oracle Database sein .

abrittaf
quelle
1

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*"')
Humayoun_Kabir
quelle
Vielen Dank. Dies sollte die akzeptierte Antwort IMO sein. Nicht jeder hat einen definierten Volltextindex (was auch immer das bedeutet). Ihre ersten Vorschläge wirken wie ein Zauber. Sie können die Platzhalter sogar in die temporären Tabellenwerte selbst einfügen, anstatt sie auf dem LIKE zu verketten.
Der Narr
0

Keine Antwort wie diese:

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

Im Orakel kein Problem.

Hong Van Vit
quelle
0

In Teradata können Sie verwenden LIKE ANY ('%ABC%','%PQR%','%XYZ%'). Unten ist ein Beispiel, das für mich die gleichen Ergebnisse erbracht 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%')
Piyush Verma
quelle
0

Ich weiß, dass dies sehr spät ist, aber ich hatte eine ähnliche Situation. Ich brauchte einen "Like In" -Operator für eine Reihe von gespeicherten Prozeduren, die viele Parameter akzeptieren und diese Parameter dann zum Aggregieren von Daten aus mehreren RDBMS-Systemen verwenden. Daher würden keine RDBMS-spezifischen Tricks funktionieren, jedoch die gespeicherte Prozedur und alle Funktionen wird auf MS SQL Server ausgeführt, sodass wir T-SQL für die Funktionalität zum Generieren der vollständigen SQL-Anweisungen für jedes RDBMS verwenden können, die Ausgabe muss jedoch ziemlich RDBMS-unabhängig sein.

Dies ist, was ich mir für den Moment ausgedacht habe, um eine durch Trennzeichen getrennte Zeichenfolge (z. B. einen Parameter, der in eine gespeicherte Prozedur eingeht) in einen SQL-Block umzuwandeln. Ich nenne es "Flechte" für "LIKE IN". Kapiert?

Lichen.sql

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =======================================================================
-- Lichen - Scalar Valued Function
-- Returns nvarchar(512) of "LIKE IN" results.  See further documentation.
-- CREATOR: Norman David Cooke
-- CREATED: 2020-02-05
-- UPDATED:
-- =======================================================================
CREATE OR ALTER FUNCTION Lichen 
(
    -- Add the parameters for the function here
    @leadingAnd bit = 1,
    @delimiter nchar(1) = ';',
    @colIdentifier nvarchar(64),
    @argString nvarchar(256)
)
RETURNS nvarchar(512)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @result nvarchar(512)

    -- set delimiter to detect (add more here to detect a delimiter if one isn't provided)
    DECLARE @delimit nchar(1) = ';'
    IF NOT @delimiter = @delimit 
        SET @delimit = @delimiter


    -- check to see if we have any delimiters in the input pattern
    IF CHARINDEX(@delimit, @argString) > 1  -- check for the like in delimiter
    BEGIN  -- begin 'like in' branch having found a delimiter
        -- set up a table variable and string_split the provided pattern into it.
        DECLARE @lichenTable TABLE ([id] [int] IDENTITY(1,1) NOT NULL, line NVARCHAR(32))
        INSERT INTO @lichenTable SELECT * FROM STRING_SPLIT(@argString, ';')

        -- setup loop iterators and determine how many rows were inserted into lichen table
        DECLARE @loopCount int = 1
        DECLARE @lineCount int 
        SELECT @lineCount = COUNT(*) from @lichenTable

        -- select the temp table (to see whats inside for debug)
        --select * from @lichenTable

        -- BEGIN AND wrapper block for 'LIKE IN' if bit is set
        IF @leadingAnd = 1
            SET @result = ' AND ('
        ELSE
            SET @result = ' ('

        -- loop through temp table to build multiple "LIKE 'x' OR" blocks inside the outer AND wrapper block
        WHILE ((@loopCount IS NOT NULL) AND (@loopCount <= @lineCount))
        BEGIN -- begin loop through @lichenTable
            IF (@loopcount = 1) -- the first loop does not get the OR in front
                SELECT @result = CONCAT(@result, ' ', @colIdentifier, ' LIKE ''', line, '''') FROM @lichenTable WHERE id = @loopCount
            ELSE  -- but all subsequent loops do
                SELECT @result = CONCAT(@result, ' OR ', @colIdentifier, ' LIKE ''', line, '''') FROM @lichenTable WHERE id = @loopCount
            SET @loopcount = @loopCount + 1     -- increment loop
        END -- end loop through @lichenTable

        -- set final parens after lichenTable loop
        SET @result = CONCAT(@result, ' )')
    END  -- end 'like in' branch having found a delimiter
    ELSE -- no delimiter was provided
    BEGIN   -- begin "no delimiter found" branch
        IF @leadingAnd = 1 
            SET @result = CONCAT(' AND ', @colIdentifier, ' LIKE ''' + @argString + '''')
        ELSE
            SET @result = CONCAT(' ', @colIdentifier, ' LIKE ''' + @argString + '''')
    END     -- end "no delimiter found" branch

    -- Return the result of the function
    RETURN @result
END  -- end lichen function

GO

Die Trennzeichenerkennung ist möglicherweise geplant, aber im Moment wird standardmäßig ein Semikolon verwendet, sodass Sie sie einfach defaultdort einfügen können . Es gibt wahrscheinlich Fehler darin. Der @leadingAndParameter ist nur ein Bitwert, um zu bestimmen, ob ein führendes "UND" vor dem Block stehen soll, damit er gut zu anderen Ergänzungen der WHERE-Klausel passt.

Beispielverwendung (mit Trennzeichen in argString)

SELECT [dbo].[Lichen] (
   default        -- @leadingAND, bit, default: 1
  ,default        -- @delimiter, nchar(1), default: ';'
  ,'foo.bar'      -- @colIdentifier, nvarchar(64), this is the column identifier
  ,'01%;02%;%03%' -- @argString, nvarchar(256), this is the input string to parse "LIKE IN" from
)
GO

Gibt einen nvarchar (512) zurück, der Folgendes enthält:

 AND ( foo.bar LIKE '01%' OR foo.bar LIKE '02%' OR foo.bar LIKE '%03%' ) 

Der Block wird auch übersprungen, wenn die Eingabe kein Trennzeichen enthält:

Beispielverwendung (ohne Trennzeichen in argString)

SELECT [dbo].[Lichen] (
   default        -- @leadingAND, bit, default: 1
  ,default        -- @delimiter, nchar(1), default: ';'
  ,'foo.bar'      -- @colIdentifier, nvarchar(64), this is the column identifier
  ,'01%'          -- @argString, nvarchar(256), this is the input string to parse "LIKE IN" from
)
GO

Gibt einen nvarchar (512) zurück, der Folgendes enthält:

 AND foo.bar LIKE '01%'

Ich werde weiter daran arbeiten. Wenn ich also etwas übersehen habe (offensichtlich oder auf andere Weise), können Sie dies gerne kommentieren oder erreichen.

NDC
quelle
-3

mach das

WHERE something + '%' in ('bla', 'foo', 'batz')
OR '%' + something + '%' in ('tra', 'la', 'la')

oder

WHERE something + '%' in (select col from table where ....)
Nikolay Hristov
quelle
1
Wie wird das funktionieren? Die LHS ist eine Zeichenfolge mit einem%, und dieses% ist daher kein Platzhalter
Darius X.