Existe-t-il une combinaison de «LIKE» et «IN» dans SQL?

341

En SQL, je dois (malheureusement) souvent utiliser des LIKEconditions " " dues à des bases de données qui violent presque toutes les règles de normalisation. Je ne peux pas changer ça maintenant. Mais cela n'a rien à voir avec la question.

De plus, j'utilise souvent des conditions comme WHERE something in (1,1,2,3,5,8,13,21)pour une meilleure lisibilité et flexibilité de mes instructions SQL.

Existe-t-il un moyen possible de combiner ces deux choses sans écrire de sous-sélections compliquées?

Je veux quelque chose d'aussi simple qu'au WHERE something LIKE ('bla%', '%foo%', 'batz%')lieu de cela:

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

Je travaille avec SQl Server et Oracle ici mais je suis intéressé si cela est possible dans n'importe quel SGBDR.

selfawaresoup
la source
1
Vous devez faire et aimer ou: ET (quelque chose COMME '% chose%' ou quelque chose COMME '% chose%' ou quelque chose COMME '% thing%')
Cosmic Hawk
Je souhaite que nous ayons eu Teradata like any/ like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-all . (Pour mémoire, cela a été demandé sur le forum Oracle Community Ideas community.oracle.com/ideas/11592 )
William Robertson

Réponses:

196

Il n'y a pas de combinaison de LIKE & IN dans SQL, encore moins dans TSQL (SQL Server) ou PLSQL (Oracle). Cela s'explique en partie par le fait que la recherche en texte intégral (FTS) est l'alternative recommandée.

Les implémentations Oracle et SQL Server FTS prennent en charge le mot clé CONTAINS, mais la syntaxe est toujours légèrement différente:

Oracle:

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

Serveur SQL:

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

La colonne que vous interrogez doit être indexée en texte intégral.

Référence:

Poneys OMG
la source
11
Salut, avec Oracle, vous devez créer des index en clair sur les colonnes auxquelles vous souhaitez appliquer l'opérateur "CONTAINS". En fonction de votre volume de données, cela peut être assez long.
Pierre-Gilles Levallois
18
Avec SQL Server (au moins la version 2008), le commentaire de @Pilooz s'applique également, vous devez créer des index de texte intégral.
Marcel
La longueur maximale est de 4000.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
59

Si vous souhaitez rendre votre relevé facilement lisible, vous pouvez utiliser REGEXP_LIKE (disponible à partir d'Oracle version 10).

Un exemple de tableau:

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.

La syntaxe d'origine:

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.

Et une requête simple avec REGEXP_LIKE

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

SOMETH
------
blabla
ofooof
batzzz

3 rows selected.

MAIS ...

Je ne le recommanderais pas moi-même en raison des performances pas si bonnes. Je m'en tiendrai aux différents prédicats LIKE. Donc, les exemples étaient juste pour le plaisir.

Rob van Wijk
la source
4
+1 belle illustration de l'utilisation de REGEXP en 10g. Je suis curieux, cependant, si les performances seraient vraiment bien pires. Les deux nécessiteront des analyses complètes de table et / ou d'index, non?
DCookie
12
Vrai. Mais les expressions régulières brûlent le CPU comme un fou, pas les E / S. Si c'est pire et combien c'est pire, cela dépend de la taille de votre liste d'expressions et si la colonne est indexée ou non, entre autres. C'est juste un avertissement, afin que l'affiche originale ne soit pas surprise quand il commence à la mettre en œuvre.
Rob van Wijk
49

vous êtes coincé avec le

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

sauf si vous remplissez une table temporaire (incluez les caractères génériques avec les données) et joignez-vous comme ceci:

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

essayez-le (en utilisant la syntaxe SQL Server):

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

PRODUCTION:

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

(2 row(s) affected)

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

(2 row(s) affected)
KM.
la source
Ok, cela fonctionnerait, mais cela ne va pas dans la direction que je souhaite rendre la déclaration SQL plus facilement lisible :)
selfawaresoup
10
en SQL, vous allez pour l'utilisation et les performances de l'index. Utilisez uniquement l'indentation et la dénomination pour la lisibilité SQL, lorsque vous effectuez d'autres modifications pour la lisibilité, vous risquez de changer le plan d'exécution (ce qui affecte l'utilisation et les performances de l'index). Si vous ne faites pas attention, vous pouvez facilement changer une requête en cours d'exécution en une requête très lente en apportant des modifications triviales.
KM.
La première déclaration de cette réponse est la clé - (la plupart?) Les systèmes et langages basés sur SQL ne prennent pas en charge ce que vous voulez, non sans implémenter des solutions de contournement. (Dans SQL Server, l'indexation de texte intégral serait-elle utile?)
Philip Kelley
@Philip Kelley, l'indexation de texte intégral de SQL Server peut-elle le faire LIKE 'bla%' , ce qui dans l'exemple de code de l'OP? ou peut-il seulement effectuer des LIKE '%bla%'recherches?
KM.
Honnêtement, je ne sais pas, je n'ai jamais utilisé l'indexation FT. Je l'ai ajouté en tant qu'échantillon d'une solution de contournement possible déjà incluse dans le produit. Pour ce qu'il fait (A ou B ou C), je soupçonne qu'il ne le fait pas, je suis assez confiant qu'il faudrait beaucoup d'efforts pour le déterminer, et je sais que cela sort du cadre de sa question initiale (est-ce que SQL le fait nativement).
Philip Kelley
20

Avec PostgreSQL, il existe la forme ANYor ALL:

WHERE col LIKE ANY( subselect )

ou

WHERE col LIKE ALL( subselect )

où la sous-sélection renvoie exactement une colonne de données.

Benoit
la source
1
Sont LIKE ANYet sont LIKE ALLcommuns à tous les dialectes SQL, c'est-à-dire faisant partie du langage principal, ou spécifiques à un dialecte?
Assad Ebrahim
1
@AssadEbrahim, non, ils sont spécifiques. Oracle a = ANYou <> ALLmais il ne fonctionne qu'en SQL, pas en PLSQL par exemple.
Benoit
Je pense que c'est la syntaxe standard (mais peu de SGBD l'ont implémentée)
ypercubeᵀᴹ
Pour les postgres, voir stackoverflow.com/questions/2245536/…
rogerdpack
13

Une autre solution, devrait fonctionner sur n'importe quel SGBDR:

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
la source
1
Mais c'est plus laid qu'un ensemble d'instructions OR
Fandango68
1
@ Fandango68, mais l'union des sélections peut être remplacée par une autre source de motifs comme une table, une vue, etc.
mik
10

Je suggère d'utiliser une fonction utilisateur TableValue si vous souhaitez encapsuler les techniques de jointure interne ou de table temporaire illustrées ci-dessus. Cela lui permettrait de lire un peu plus clairement.

Après avoir utilisé la fonction de partage définie sur: http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

nous pouvons écrire ce qui suit sur la base d'un tableau que j'ai créé appelé "Fish" (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.

Les sorties

1 basse
2 brochets
7 pêcheur
8 doré
Nerd célèbre
la source
1
Une ligne sera dupliquée si elle correspond à plusieurs conditions à la fois.
mik
7

Une approche consisterait à stocker les conditions dans une table temporaire (ou variable de table dans SQL Server) et à y adhérer comme ceci:

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
AdaTheDev
la source
Une ligne sera dupliquée si elle correspond à plusieurs conditions à la fois.
mik
7

Utilisez plutôt une jointure interne:

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
la source
1
Eh bien, c'est exactement ce que j'aimerais éviter. Bien que ça marche.
selfawaresoup
Pourquoi éviter cette solution? Il fonctionne aussi vite que la solution acceptée et est tout aussi polyvalent.
Phil Factor
3
@PhilFactor Cette solution peut créer des lignes en double.
Jakub Kania
5

Je travaille avec SQl Server et Oracle ici mais je suis intéressé si cela est possible dans n'importe quel SGBDR.

Teradata prend en charge la syntaxe LIKE ALL / ANY :

TOUTES les chaînes de la liste.
N'IMPORTE QUELLE chaîne dans la 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%'                    
└──────────────────────────────┴────────────────────────────────────┘

ÉDITER:

jOOQ version 3.12.0 prend en charge cette syntaxe:

Ajouter des opérateurs synthétiques [NOT] LIKE ANY et [NOT] LIKE ALL

Souvent, les utilisateurs de SQL souhaiteraient pouvoir combiner les prédicats LIKE et IN, comme dans:

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

La solution de contournement consiste à étendre manuellement le prédicat à l'équivalent

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

jOOQ pourrait prendre en charge un tel prédicat synthétique hors de la boîte.


PostgreSQL LIKE/ILIKE ANY (ARRAY[]):

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

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

démo db <> fiddle


Snowflake prend également en charge la correspondance COMME TOUT / COMME TOUS :

COMME TOUT / TOUS

Permet une correspondance sensible à la casse des chaînes basée sur la comparaison avec un ou plusieurs modèles.

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

Exemple:

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

tu peux même essayer ça

Fonction

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

Requete

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
la source
4

J'ai une solution simple, qui fonctionne au moins en postgresql , en utilisant like anysuivie de la liste des expressions rationnelles. Voici un exemple, qui cherche à identifier certains antibiotiques dans une liste:

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

Je me demandais aussi quelque chose comme ça. Je viens de tester en utilisant une combinaison de SUBSTRINGet INc'est une solution efficace pour ce genre de problème. Essayez la requête ci-dessous:

Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
ssah
la source
1
un problème avec cette approche est que vous perdez la possibilité d'utiliser un index sur t1.something s'il existe ..
ShoeLace
1
cela ne trouvera jamais 'batz'
mik
3

Dans Oracle, vous pouvez utiliser une collection de la manière suivante:

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

Ici, j'ai utilisé un type de collection prédéfini ku$_vcnt, mais vous pouvez déclarer le vôtre comme ceci:

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

Pour Sql Server, vous pouvez recourir à Dynamic SQL.

La plupart du temps, dans de telles situations, le paramètre de la clause IN est basé sur certaines données de la base de données.

L'exemple ci-dessous est un peu "forcé", mais cela peut correspondre à divers cas réels trouvés dans les bases de données héritées.

Supposons que vous ayez des personnes de table où les noms de personne sont stockés dans un seul champ PersonName comme FirstName + '' + LastName. Vous devez sélectionner toutes les personnes dans une liste de prénoms, stockée dans le champ NameToSelect dans la table NamesToSelect , ainsi que certains critères supplémentaires (comme filtré sur le sexe, la date de naissance, etc.)

Vous pouvez le faire comme suit

-- @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
la source
2

J'ai peut-être une solution pour cela, même si cela ne fonctionnera que dans SQL Server 2008 pour autant que je sache. J'ai découvert que vous pouvez utiliser le constructeur de lignes décrit dans https://stackoverflow.com/a/7285095/894974 pour rejoindre une table «fictive» en utilisant une clause similaire. Cela semble plus complexe que ça, regardez:

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

Cela se traduira par tous les utilisateurs avec une adresse e-mail comme celles fournies dans la liste. J'espère que c'est utile à n'importe qui. Le problème me dérangeait depuis un moment.

Sander
la source
1
C'est intéressant. Cependant, sachez que cela ne doit être utilisé que sur une petite table car l'instruction like ne peut pas utiliser d'index. C'est pourquoi la recherche en texte intégral, bien que plus difficile à configurer initialement, est le meilleur choix si vous avez beaucoup de données.
HLGEM
2

À partir de 2016, SQL Server comprend une STRING_SPLIT fonction . J'utilise SQL Server v17.4 et j'ai obtenu que cela fonctionne pour moi:

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

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

Cela fonctionne pour les valeurs séparées par des virgules

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 ''%') + '%'')''

Évalue à:

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

Si vous souhaitez qu'il utilise des index, vous devez omettre le premier '%'caractère.

David F Mayer
la source
1

Dans Oracle RBDMS, vous pouvez obtenir ce comportement à l'aide de REGEXP_LIKE fonction .

Le code suivant testera si la chaîne trois est présente dans l'expression de liste un | deux | trois | quatre | cinq (dans lequel le symbole de tuyau " | " signifie une opération logique OU).

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

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

1 row selected.

L'expression précédente équivaut à:

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

Alors ça va réussir.

En revanche, le test suivant échouera.

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

no rows selected

Il existe plusieurs fonctions liées aux expressions régulières (REGEXP_ *) disponibles dans Oracle depuis la version 10g. Si vous êtes un développeur Oracle et que ce sujet vous intéresse, cela devrait être un bon début. Utiliser des expressions régulières avec Oracle Database .

abrittaf
la source
1

Peut-être pensez-vous que la combinaison comme celle-ci:

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

Si vous avez défini un index de texte intégral pour votre table cible, vous pouvez utiliser cette alternative:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
Humayoun_Kabir
la source
Je vous remercie. Cela devrait être la réponse acceptée OMI. Tout le monde n'a pas un index de texte intégral défini (quoi que cela signifie) Vos premières suggestions fonctionnent comme un charme. Vous pouvez même mettre les caractères génériques dans les valeurs de la table temporaire elle-même au lieu de concaténer sur le LIKE.
The Fool
0

Pas de réponse comme ça:

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

En oracle aucun problème.

Hong Van Vit
la source
0

Dans Teradata, vous pouvez utiliser LIKE ANY ('%ABC%','%PQR%','%XYZ%'). Voici un exemple qui a produit les mêmes résultats pour moi

--===========
--  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
la source
0

Je sais que c'est très tard, mais j'ai eu une situation similaire. J'avais besoin d'un opérateur "Like In" pour un ensemble de procédures stockées que j'ai, qui acceptent de nombreux paramètres et utilisent ensuite ces paramètres pour agréger les données de plusieurs systèmes RDBMS, donc aucune astuce spécifique au RDBMS ne fonctionnerait, cependant la procédure stockée et toutes les fonctions fonctionnera sur MS SQL Server, nous pouvons donc utiliser T-SQL pour la fonctionnalité de génération des instructions SQL complètes pour chaque SGBDR, mais la sortie doit être assez indépendante du SGBDR.

C'est ce que j'ai trouvé pour le moment pour transformer une chaîne délimitée (comme un paramètre entrant dans une procédure stockée) en un bloc SQL. Je l'appelle "Lichen" pour "LIKE IN". Tu piges?

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

La détection du délimiteur est peut-être planifiée, mais pour l'instant, elle est par défaut un point-virgule, vous pouvez donc simplement y mettre default. Il y a probablement des bogues dans cela. Le @leadingAndparamètre est juste une valeur de bit pour déterminer si vous voulez mettre un "ET" en tête devant le bloc afin qu'il s'intègre bien avec les autres ajouts de clause WHERE.

Exemple d'utilisation (avec délimiteur dans 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

Renvoie un nvarchar (512) contenant:

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

Il sautera également le bloc si l'entrée ne contient pas de délimiteur:

Exemple d'utilisation (sans délimiteur dans 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

Renvoie un nvarchar (512) contenant:

 AND foo.bar LIKE '01%'

Je vais continuer à travailler là-dessus, donc si j'ai oublié quelque chose (manifestement évident ou autre), n'hésitez pas à commenter ou à tendre la main.

NDC
la source
-3

fais ça

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

ou

WHERE something + '%' in (select col from table where ....)
Nikolay Hristov
la source
1
Comment ça va marcher? Le LHS est une chaîne avec un%, et ce% n'est donc pas un caractère générique
Darius X.