Question Y a-t-il une combinaison de "LIKE" et "IN" dans SQL?


En SQL j'ai (malheureusement) souvent à utiliser "LIKE"conditions dues à des bases de données qui violent presque toutes les règles de normalisation. Je ne peux pas changer cela pour le moment. 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.

Est-il possible de combiner ces deux choses sans écrire des sous-sélections compliquées?

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

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 tout SGBDR.


258
2018-06-10 13:44


origine


Réponses:


Il n'y a pas de combinaison de LIKE & IN en SQL, et encore moins de TSQL (SQL Server) ou de PLSQL (Oracle). Une partie de la raison en est 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 encore 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*"')

Référence:


159
2018-06-10 17:34



Si vous souhaitez que votre déclaration soit facilement lisible, vous pouvez utiliser REGEXP_LIKE (disponible à partir de la version Oracle 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 originale:

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 de la performance pas si bonne. Je collerais avec les plusieurs prédicats de LIKE. Donc les exemples étaient juste pour s'amuser.


53
2018-06-10 14:19



vous êtes coincé avec le

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

sauf si vous remplissez une table temporaire (ajoutez les caractères génériques aux données) et joignez-vous à 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

SORTIE:

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

(2 row(s) affected)

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

(2 row(s) affected)

41
2018-06-10 13:48



Avec PostgreSQL, il y a le ANY ou ALL forme:

WHERE col LIKE ANY( subselect )

ou

WHERE col LIKE ALL( subselect )

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


18
2018-04-21 09:17



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

Après avoir utilisé la fonction split définie à: 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'une table que j'ai créée appelée "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é

10
2018-06-10 17:18



Une solution consisterait à stocker les conditions dans une table temporaire (ou une variable de table dans SQL Server) et à y joindre les éléments suivants:

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

7
2018-06-10 13:48



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

7
2018-06-10 16:35



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)

5
2017-10-18 09:54



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

Question

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

4
2018-04-23 11:37



Pour SQL Server, vous pouvez recourir à SQL dynamique.

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 à plusieurs cas réels trouvés dans les bases de données existantes.

Supposons que vous ayez une table Personnes où les noms de personnes sont stockés dans un seul champ Nom d'une personne comme prénom + '' + LastName. Vous devez sélectionner toutes les personnes dans une liste de prénoms, stockée dans le champ NameToSelect dans le tableau NamesToSelect, plus quelques 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

2
2018-06-15 14:42