Czy istnieje kombinacja „LIKE” i „IN” w SQL?

341

W SQL ja (niestety) często muszę używać LIKEwarunków z powodu baz danych, które naruszają prawie każdą zasadę normalizacji. Nie mogę tego teraz zmienić. Ale to nie ma znaczenia dla pytania.

Ponadto często używam warunków, takich jak WHERE something in (1,1,2,3,5,8,13,21)lepsza czytelność i elastyczność moich instrukcji SQL.

Czy jest jakiś sposób na połączenie tych dwóch rzeczy bez pisania skomplikowanych podselekcji?

Chcę czegoś tak prostego jak WHERE something LIKE ('bla%', '%foo%', 'batz%')zamiast tego:

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

Pracuję tutaj z SQl Server i Oracle, ale jestem zainteresowany, czy jest to w ogóle możliwe w dowolnym RDBMS.

selfawaresoup
źródło
1
Musisz zrobić i lubić lub: ORAZ (coś LIKE „% rzecz%” lub coś LIKE „% rzecz%” lub coś LIKE „% rzecz%”)
Cosmic Hawk
Żałuję, że nie mieliśmy Teradata like any/ like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-all . (Dla przypomnienia, zostało to zamówione na forum Oracle Community Ideas community.oracle.com/ideas/11592 )
William Robertson,
podobny stackoverflow.com/q/1076097/125981
Mark Schultheiss,

Odpowiedzi:

196

Nie ma kombinacji LIKE i IN w SQL, a tym bardziej w TSQL (SQL Server) lub PLSQL (Oracle). Wynika to częściowo z tego, że wyszukiwanie pełnotekstowe (FTS) jest zalecaną alternatywą.

Zarówno implementacje FTS Oracle, jak i SQL Server obsługują słowo kluczowe CONTAINS, ale składnia jest nadal nieco inna:

Wyrocznia:

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

SQL Server:

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

Zapytana kolumna musi być indeksowana pełnotekstowo.

Odniesienie:

Kucyki OMG
źródło
11
Cześć, w przypadku Oracle musisz zbudować indeksy jawnego tekstu na kolumnach, które chcesz zastosować operator „ZAWIERA”. W zależności od ilości danych może to być dość długie.
Pierre-Gilles Levallois,
18
W SQL Server (przynajmniej w wersji 2008) komentarz @Pilooz również ma zastosowanie, musisz zbudować indeksy pełnotekstowe.
Marcel
Maksymalna długość to 4000.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
59

Jeśli chcesz, aby twoje oświadczenie było łatwe do odczytania, możesz użyć REGEXP_LIKE (dostępne od wersji Oracle 10 lub nowszej).

Przykładowa tabela:

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.

Oryginalna składnia:

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.

I proste zapytanie z REGEXP_LIKE

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

SOMETH
------
blabla
ofooof
batzzz

3 rows selected.

ALE ...

Nie poleciłbym tego sam ze względu na niezbyt dobre wyniki. Trzymałbym się kilku predykatów LIKE. Przykłady były więc dla zabawy.

Rob van Wijk
źródło
4
+1 ładna ilustracja użycia REGEXP w 10g. Jestem jednak ciekawy, czy wydajność byłaby o wiele gorsza. Oba będą wymagać pełnego skanowania tabeli i / lub indeksów, prawda?
DCookie
12
Prawdziwe. Ale wyrażenia regularne palą procesor jak szalony, a nie we / wy. Jeśli jest gorzej i o ile gorzej, zależy od tego, jak duża jest twoja lista wyrażeń i od tego, czy kolumna jest indeksowana, czy nie. To tylko ostrzeżenie, aby oryginalny plakat nie był zaskoczony, gdy zacznie go wdrażać.
Rob van Wijk
49

utknąłeś z

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

chyba że zapełnisz tabelę tymczasową (dołącz do danych symbole wieloznaczne) i dołączysz w ten sposób:

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

wypróbuj (używając składni 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

WYNIK:

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

(2 row(s) affected)

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

(2 row(s) affected)
KM.
źródło
Ok, to by działało, ale nie idzie to w moim zamierzonym kierunku, aby uczynić instrukcję SQL łatwiejszą do odczytania :)
selfawaresoup
10
w SQL wybierasz użycie i wydajność indeksu. Wcięcia i nazewnictwo należy stosować tylko w celu zapewnienia czytelności SQL, gdy wprowadzane są inne modyfikacje, tylko ryzykuje się zmianę planu wykonania (co wpływa na użycie i wydajność indeksu). Jeśli nie jesteś ostrożny, możesz łatwo zmienić szybko działające zapytanie na bardzo wolne, wprowadzając trywialne zmiany.
KM.
Pierwsze stwierdzenie tej odpowiedzi jest kluczowe - (większość?) Systemy i języki oparte na SQL nie obsługują tego, co chcesz, nie bez implementacji obejść. (Czy na serwerze SQL byłoby pomocne indeksowanie pełnotekstowe?)
Philip Kelley
@Pilil Kelley, czy indeksacja pełnotekstowa SQL Server może zrobić LIKE 'bla%' , co w przykładowym kodzie OP? czy może tylko LIKE '%bla%'wyszukiwać?
KM.
Naprawdę nie wiem, nigdy nie korzystałem z indeksowania FT. Wrzuciłem to jako próbkę możliwego obejścia, które jest już zawarte w produkcie. Jeśli chodzi o to, co robi (A, B lub C), podejrzewam, że to nie robi, jestem dość pewny, że ustalenie tego wymagałoby dużo wysiłku i wiem, że jest to poza zakresem jego pierwotnego pytania (czy SQL zrób to natywnie).
Philip Kelley,
20

W PostgreSQL dostępna jest forma ANYlub ALL:

WHERE col LIKE ANY( subselect )

lub

WHERE col LIKE ALL( subselect )

gdzie podselekcja zwraca dokładnie jedną kolumnę danych.

Benoit
źródło
1
Czy LIKE ANYi LIKE ALLwspólne dla wszystkich dialektów SQL, czyli częścią języka rdzenia lub specyficzne dla dialektu?
Assad Ebrahim
1
@AssadEbrahim, nie, są one specyficzne. Oracle ma = ANYlub <> ALLdziała tylko w języku SQL, a nie na przykład w PLSQL.
Benoit,
Myślę, że jest to standardowa składnia (ale niewiele DBMS ją zaimplementowało)
ypercubeᵀᴹ
Postgres można
13

Inne rozwiązanie powinno działać na każdym RDBMS:

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
źródło
1
Ale jest brzydszy niż zestaw instrukcji OR
Fandango68,
1
@ Fandango68, ale związek selekcji można zastąpić innym źródłem wzorców, takich jak stół, widok itp.
mik
10

Sugerowałbym użycie funkcji użytkownika TableValue, jeśli chcesz enkapsulować techniki łączenia wewnętrznego lub tabeli temp. Pokazane powyżej. Pozwoliłoby to na bardziej czytelne czytanie.

Po użyciu funkcji podziału zdefiniowanej w: stronie http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

możemy napisać następujące na podstawie utworzonej przeze mnie tabeli o nazwie „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.

Wyjścia

1 bas
2 szczupaki
7 Wędkarz
8 Walleye
Famous Nerd
źródło
1
Wiersz zostanie zduplikowany, jeśli zostanie spełniony wiele warunków jednocześnie.
mik
7

Jednym z podejść byłoby przechowywanie warunków w tabeli tymczasowej (lub zmiennej tabeli w SQL Server) i dołączanie do tego w następujący sposób:

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
AdaTheDev
źródło
Wiersz zostanie zduplikowany, jeśli zostanie spełniony wiele warunków jednocześnie.
mik
7

Zamiast tego użyj sprzężenia wewnętrznego:

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
źródło
1
Właśnie tego chciałbym uniknąć. Chociaż to działa.
selfawaresoup
Dlaczego warto unikać tego rozwiązania? Działa tak szybko, jak przyjęte rozwiązanie i jest równie wszechstronny.
Phil Factor
3
@PhilFactor To rozwiązanie może tworzyć duplikaty wierszy.
Jakub Kania,
5

Pracuję tutaj z SQl Server i Oracle, ale jestem zainteresowany, czy jest to w ogóle możliwe w dowolnym RDBMS.

Teradata obsługuje składnię LIKE ALL / ANY :

WSZYSTKIE wszystkie ciągi na liście.
DOWOLNY dowolny ciąg na liście.

┌──────────────────────────────┬────────────────────────────────────┐
      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%'                    
└──────────────────────────────┴────────────────────────────────────┘

EDYTOWAĆ:

Wersja 3.12.0 jOOQ obsługuje tę składnię:

Dodaj syntetyczne [NIE] PODOBNE DO DOWOLNYCH i [NIE] PODOBNE DO WSZYSTKICH operatorów

Wiele razy użytkownicy SQL chcieliby łączyć predykaty LIKE i IN, jak w:

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

Obejściem tego problemu jest ręczne rozwinięcie predykatu do ekwiwalentu

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

jOOQ może obsługiwać taki syntetyczny predykat po wyjęciu z pudełka.


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 <> demo skrzypiec


Snowflake obsługuje również dopasowanie LIKE ANY / LIKE ALL :

JAK KAŻDY / WSZYSTKO

Umożliwia dopasowanie ciągów znaków z uwzględnieniem wielkości liter na podstawie porównania z jednym lub większą liczbą wzorców.

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

Przykład:

SELECT * 
FROM like_example 
WHERE subject LIKE ANY ('%Jo%oe%','T%e')
-- WHERE subject LIKE ALL ('%Jo%oe%','J%e')
Łukasz Szozda
źródło
4

możesz nawet spróbować tego

Funkcjonować

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

Pytanie

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
źródło
4

Mam proste rozwiązanie, które działa co najmniej w Postgresql , używając like anynastępującej po nim listy wyrażeń regularnych. Oto przykład identyfikujący niektóre antybiotyki na liście:

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

Zastanawiałem się również nad czymś takim. Właśnie przetestowałem przy użyciu kombinacji SUBSTRINGi INjest to skuteczne rozwiązanie dla tego rodzaju problemu. Wypróbuj poniższe zapytanie:

Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
ssah
źródło
1
Jednym z problemów z tym podejściem jest to, że tracisz możliwość używania indeksu na t1. coś, jeśli istnieje.
ShoeLace
1
to nigdy nie znajdzie „batz”
mik
3

W Oracle możesz użyć kolekcji w następujący sposób:

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

Tutaj użyłem predefiniowanego typu kolekcji ku$_vcnt, ale możesz zadeklarować swój własny:

CREATE TYPE my_collection AS TABLE OF VARCHAR2(4000);
mik
źródło
2

W przypadku Sql Server możesz skorzystać z Dynamic SQL.

Przez większość czasu w takich sytuacjach masz parametr klauzuli IN oparty na niektórych danych z bazy danych.

Poniższy przykład jest trochę „wymuszony”, ale może pasować do różnych rzeczywistych przypadków znalezionych w starszych bazach danych.

Załóżmy, że masz w tabeli Osoby, w których nazwiska osób są przechowywane w jednym polu PersonName jako FirstName + '' + LastName. Musisz wybrać wszystkie osoby z listy imion przechowywanych w polu NameToSelect w tabeli NamesToSelect , oraz dodatkowych kryteriów (takich jak filtrowane według płci, daty urodzenia itp.)

Możesz to zrobić w następujący sposób

-- @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
źródło
2

Mogę mieć na to rozwiązanie, chociaż o ile wiem, będzie działać tylko w SQL Server 2008. Odkryłem, że możesz użyć konstruktora wierszy opisanego w https://stackoverflow.com/a/7285095/894974, aby dołączyć do tabeli „fikcyjnej” przy użyciu klauzuli like. To brzmi bardziej skomplikowane niż jest, spójrz:

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

Spowoduje to, że wszyscy użytkownicy otrzymają adres e-mail, taki jak podany na liście. Mam nadzieję, że przyda się każdemu. Problemem przeszkadzało mi trochę.

Szlifierka
źródło
1
To interesujące. Należy jednak pamiętać, że należy tego używać tylko w tabeli smal, ponieważ instrukcja like nie może używać indeksów. Dlatego wyszukiwanie pełnotekstowe, choć trudniejsze do skonfigurowania, jest lepszym wyborem, jeśli masz dużo danych.
HLGEM
2

Począwszy od 2016 r. SQL Server zawiera STRING_SPLIT funkcję . Korzystam z programu SQL Server 17.4 i mam to do pracy:

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

SELECT * from Project p
JOIN STRING_SPLIT(@dashboard, ',') AS sp ON p.ProjectNumber LIKE sp.value
znak
źródło
1

Działa to w przypadku wartości oddzielonych przecinkami

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

Ocenia:

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

Jeśli chcesz używać indeksów, musisz pominąć pierwszy '%'znak.

David F. Mayer
źródło
1

W Oracle RBDMS można to osiągnąć za pomocą funkcji REGEXP_LIKE .

Poniższy kod sprawdzi, czy ciąg trzeci jest obecny w wyrażeniu listy jeden | dwa | trzy | cztery | pięć (w którym symbol potoku „ | ” oznacza operację logiczną LUB).

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

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

1 row selected.

Poprzednie wyrażenie jest równoważne z:

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

Więc to się uda.

Z drugiej strony następujący test zakończy się niepowodzeniem.

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

no rows selected

Istnieje kilka funkcji związanych z wyrażeniami regularnymi (REGEXP_ *) dostępnych w Oracle od wersji 10g. Jeśli jesteś programistą Oracle i interesujesz się tym tematem, powinien to być dobry początek korzystania z wyrażeń regularnych z bazą danych Oracle .

abrittaf
źródło
1

Być może uważasz, że taka kombinacja:

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

Jeśli zdefiniowałeś indeks pełnotekstowy dla tabeli docelowej, możesz użyć tej alternatywy:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
Humayoun_Kabir
źródło
Dziękuję Ci. To powinna być zaakceptowana odpowiedź IMO. Nie każdy ma zdefiniowany indeks pełnotekstowy (cokolwiek to znaczy) Twoje pierwsze sugestie działają jak urok. Możesz nawet umieścić symbole wieloznaczne w samych wartościach tabeli tymczasowej zamiast łączyć się w LIKE.
Głupiec,
0

Brak takiej odpowiedzi:

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

W wyroczni nie ma problemu.

Hong Van Vit
źródło
0

W Teradata możesz użyć LIKE ANY ('%ABC%','%PQR%','%XYZ%'). Poniżej znajduje się przykład, który przyniósł mi takie same wyniki

--===========
--  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
źródło
0

Wiem, że jest bardzo późno, ale miałem podobną sytuację. Potrzebowałem operatora „Like In” dla zestawu procedur przechowywanych, które mam, które akceptują wiele parametrów, a następnie używają tych parametrów do agregowania danych z wielu systemów RDBMS, więc żadne sztuczki specyficzne dla RDBMS nie działałyby, jednak procedura przechowywana i wszelkie funkcje będzie działać na MS SQL Server, więc możemy użyć T-SQL do funkcji generowania pełnych instrukcji SQL dla każdego RDBMS, ale dane wyjściowe muszą być dość niezależne od RDBMS.

To właśnie wymyśliłem na chwilę, aby zamienić ciąg znaków (taki jak parametr wchodzący do procedury składowanej) w blok SQL. Nazywam to „Licheń” dla „LIKE IN”. Zdobyć?

Liszaj.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

Wykrywanie ogranicznika jest prawdopodobnie planowane, ale na razie domyślnie jest to średnik, więc możesz po prostu defaulttam wstawić . Prawdopodobnie są w tym błędy. Ten @leadingAndparametr jest tylko niewielką wartością, aby ustalić, czy chcesz wstawić przed blokiem wiodące „I”, aby dobrze pasowało do innych dodatków klauzul WHERE.

Przykład użycia (z separatorem w 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

Zwróci nvarchar (512) zawierający:

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

Pominie również blok, jeśli dane wejściowe nie zawierają ogranicznika:

Przykład użycia (bez separatora w 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

Zwróci nvarchar (512) zawierający:

 AND foo.bar LIKE '01%'

Mam zamiar kontynuować prace nad tym, więc jeśli coś przeoczyłem (rażąco oczywiste lub w inny sposób), prosimy o komentarz lub kontakt.

NDC
źródło
-3

Zrób to

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

lub

WHERE something + '%' in (select col from table where ....)
Nikołaj Hristow
źródło
1
Jak to będzie działać? LHS jest ciągiem z%, a tym samym% nie jest symbolem wieloznacznym
Darius X.