Apakah ada kombinasi "LIKE" dan "IN" dalam SQL?

341

Dalam SQL I (sayangnya) sering harus menggunakan LIKEkondisi " " karena database yang melanggar hampir setiap aturan normalisasi. Saya tidak bisa mengubahnya sekarang. Tapi itu tidak relevan dengan pertanyaan itu.

Selanjutnya, saya sering menggunakan kondisi seperti WHERE something in (1,1,2,3,5,8,13,21)untuk keterbacaan yang lebih baik dan fleksibilitas pernyataan SQL saya.

Apakah ada cara yang mungkin untuk menggabungkan kedua hal ini tanpa menulis sub-seleksi yang rumit?

Saya menginginkan sesuatu semudah WHERE something LIKE ('bla%', '%foo%', 'batz%')ini:

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

Saya bekerja dengan SQl Server dan Oracle di sini, tetapi saya tertarik jika ini dimungkinkan di RDBMS sama sekali.

selfawaresoup
sumber
1
Anda harus melakukan dan menyukai atau: DAN (sesuatu seperti '% thing%' atau sesuatu LIKE '% thing%' atau sesuatu LIKE '% thing%')
Cosmic Hawk
Saya berharap kami memiliki Teradata like any/ like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-all . (Sebagai catatan, ini telah diminta di forum Oracle Community Ideas community.oracle.com/ideas/11592 )
William Robertson

Jawaban:

196

Tidak ada kombinasi LIKE & IN di SQL, apalagi di TSQL (SQL Server) atau PLSQL (Oracle). Salah satu alasannya adalah karena Pencarian Teks Lengkap (FTS) adalah alternatif yang direkomendasikan.

Baik implementasi Oracle dan SQL Server FTS mendukung kata kunci CONTAINS, tetapi sintaksnya masih sedikit berbeda:

Peramal:

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

SQL Server:

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

Kolom yang Anda tanyakan harus diindeks teks lengkap.

Referensi:

OMG Ponies
sumber
11
Hai, dengan Oracle, Anda perlu membuat indeks plaintext pada kolom yang ingin Anda terapkan operator "CONTAINS". Bergantung pada volume data Anda, ini bisa sangat panjang.
Pierre-Gilles Levallois
18
Dengan SQL Server (setidaknya versi 2008) komentar @Pilooz juga berlaku, Anda perlu membuat indeks teks lengkap.
Marcel
Panjang maksimum adalah 4000.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
59

Jika Anda ingin membuat pernyataan Anda mudah dibaca, maka Anda dapat menggunakan REGEXP_LIKE (tersedia dari Oracle versi 10 dan seterusnya).

Tabel contoh:

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.

Sintaks asli:

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.

Dan permintaan yang tampak sederhana dengan REGEXP_LIKE

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

SOMETH
------
blabla
ofooof
batzzz

3 rows selected.

TAPI ...

Saya tidak akan merekomendasikan sendiri karena kinerjanya yang tidak begitu baik. Saya akan tetap dengan beberapa predikat LIKE. Jadi contohnya hanya untuk bersenang-senang.

Rob van Wijk
sumber
4
+1 ilustrasi bagus tentang penggunaan REGEXP dalam 10g. Saya ingin tahu, jika kinerja benar-benar jauh lebih buruk. Keduanya akan membutuhkan pemindaian tabel dan / atau indeks penuh, bukan?
DCookie
12
Benar. Tapi ekspresi reguler membakar CPU seperti orang gila, bukan I / O. Jika lebih buruk dan seberapa parahnya, tergantung pada seberapa besar daftar ekspresi Anda dan apakah kolom diindeks atau tidak, antara lain. Itu hanya peringatan, agar poster aslinya tidak terkejut ketika dia mulai mengimplementasikannya.
Rob van Wijk
49

Anda terjebak dengan

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

kecuali Anda mengisi tabel temp (sertakan wild card dengan data) dan bergabunglah seperti ini:

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

coba (menggunakan sintaks 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

KELUARAN:

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

(2 row(s) affected)

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

(2 row(s) affected)
KM.
sumber
Ok, ini akan berhasil, tapi itu tidak mengarah ke tujuan saya membuat pernyataan SQL lebih mudah dibaca :)
selfawaresoup
10
dalam SQL Anda menggunakan indeks dan kinerja. Hanya menggunakan indentasi dan penamaan untuk keterbacaan SQL, ketika Anda membuat modifikasi lain untuk pembacaan saja Anda berisiko mengubah rencana eksekusi (yang memengaruhi penggunaan dan kinerja indeks). Jika Anda tidak berhati-hati, Anda dapat dengan mudah mengubah kueri yang langsung berjalan menjadi sangat lambat dengan membuat perubahan sepele.
KM.
Pernyataan pertama dari jawaban ini adalah kunci - (kebanyakan?) Sistem dan bahasa berbasis SQL tidak mendukung apa yang Anda inginkan, bukan tanpa menerapkan work-arounds. (Di SQL server, apakah pengindeksan Teks Lengkap akan membantu?)
Philip Kelley
@ Philip Kelley, dapatkah pengindeksan Teks Lengkap SQL Server dilakukan LIKE 'bla%' , yang mana dalam kode contoh OP? atau hanya dapat melakukan LIKE '%bla%'pencarian?
KM.
Jujur saya tidak tahu, saya tidak pernah menggunakan pengindeksan FT. Saya melemparkannya sebagai sampel kemungkinan penyelesaian yang sudah termasuk dalam produk. Untuk apa yang dia lakukan (A atau B atau C), saya curiga tidak melakukannya, saya cukup yakin bahwa akan membutuhkan banyak upaya untuk menentukan ini, dan tahu bahwa itu di luar ruang lingkup pertanyaan aslinya (tidak SQL melakukannya secara native).
Philip Kelley
20

Dengan PostgreSQL ada ANYatau ALLbentuk:

WHERE col LIKE ANY( subselect )

atau

WHERE col LIKE ALL( subselect )

di mana subselect mengembalikan tepat satu kolom data.

Benoit
sumber
1
Apakah LIKE ANYdan LIKE ALLumum untuk semua dialek SQL, yaitu bagian dari bahasa inti, atau khusus untuk dialek?
Assad Ebrahim
1
@ AssadEbrahim, tidak khusus. Oracle memiliki = ANYatau <> ALLtetapi hanya berfungsi dalam SQL, bukan dalam PLSQL misalnya.
Benoit
Saya pikir ini adalah sintaks standar (tetapi tidak banyak DBMS yang mengimplementasikannya)
ypercubeᵀᴹ
Untuk postgres, lihat stackoverflow.com/questions/2245536/…
rogerdpack
13

Solusi lain, harus bekerja pada RDBMS apa pun:

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
sumber
1
Tapi ini lebih buruk daripada seperangkat pernyataan ATAU
Fandango68
1
@ Fandango68, tetapi penyatuan pilihan dapat digantikan oleh sumber pola lain seperti tabel, tampilan, dll.
mik
10

Saya menyarankan menggunakan fungsi pengguna TableValue jika Anda ingin merangkum teknik Inner Join atau tabel tempa yang ditunjukkan di atas. Ini akan memungkinkannya untuk membaca sedikit lebih jelas.

Setelah menggunakan fungsi pemisahan didefinisikan di: http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

kita dapat menulis yang berikut berdasarkan tabel yang saya buat bernama "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.

Keluaran

1 Bass
2 Pike
7 Pemancing
8 Walleye
Nerd terkenal
sumber
1
Baris akan digandakan jika dicocokkan dengan banyak kondisi sekaligus.
mik
7

Salah satu pendekatan akan menyimpan kondisi dalam tabel temp (atau variabel tabel di SQL Server) dan bergabung dengan yang seperti ini:

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
AdaTheDev
sumber
Baris akan digandakan jika dicocokkan dengan banyak kondisi sekaligus.
mik
7

Gunakan gabung bagian dalam sebagai gantinya:

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
sumber
1
Ya, itulah yang ingin saya hindari. Meskipun berhasil.
selfawaresoup
Mengapa menghindari solusi ini? Ini bekerja secepat solusi yang diterima, dan sama serbaguna.
Phil Factor
3
@ PhilFactor Solusi ini dapat membuat baris duplikat.
Jakub Kania
5

Saya bekerja dengan SQl Server dan Oracle di sini, tetapi saya tertarik jika ini dimungkinkan di RDBMS sama sekali.

Teradata mendukung LIKE ALL / ANY syntax:

SEMUA setiap string dalam daftar.
SETIAP string apa pun dalam daftar.

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

EDIT:

jOOQ versi 3.12.0 mendukung sintaks itu:

Tambahkan sintetis [TIDAK] SEPERTI APAPUN dan [TIDAK] SEPERTI SEMUA operator

Sering kali, pengguna SQL ingin dapat menggabungkan predikat LIKE dan IN, seperti pada:

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

Solusinya adalah untuk secara manual memperluas predikat ke yang setara

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

JOOQ dapat mendukung predikat sintetis seperti itu di luar kotak.


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 biola


Snowflake juga mendukung LIKE ANY / LIKE ALL matching:

SEPERTI APA SAJA / SEMUA

Mengizinkan pencocokan string yang peka huruf besar-kecil berdasarkan perbandingan dengan satu pola atau lebih.

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

Contoh:

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

kamu bahkan dapat mencoba ini

Fungsi

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

Pertanyaan

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
sumber
4

Saya punya solusi sederhana, yang berfungsi di postgresql setidaknya, menggunakan like anydiikuti oleh daftar regex. Berikut ini sebuah contoh, melihat mengidentifikasi beberapa antibiotik dalam daftar:

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

Saya juga bertanya-tanya untuk sesuatu seperti itu. Saya baru saja diuji menggunakan kombinasi SUBSTRINGdan INdan itu adalah solusi yang efektif untuk masalah seperti ini. Coba kueri di bawah ini:

Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
ssah
sumber
1
satu masalah dengan pendekatan ini adalah Anda kehilangan kemampuan untuk menggunakan indeks pada t1.something jika ada ..
ShoeLace
1
ini tidak akan pernah menemukan 'batz'
mik
3

Di Oracle Anda dapat menggunakan koleksi dengan cara berikut:

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

Di sini saya telah menggunakan tipe koleksi yang telah ditentukan ku$_vcnt, tetapi Anda dapat mendeklarasikan sendiri koleksi Anda seperti ini:

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

Untuk Sql Server, Anda dapat menggunakan Dynamic SQL.

Sebagian besar waktu dalam situasi seperti itu Anda memiliki parameter klausa IN berdasarkan pada beberapa data dari database.

Contoh di bawah ini sedikit "dipaksakan", tetapi ini bisa cocok dengan berbagai kasus nyata yang ditemukan di database lawas.

Misalkan Anda memiliki tabel Orang di mana nama orang disimpan dalam satu bidang, PersonName sebagai FirstName + '' + LastName. Anda harus memilih semua orang dari daftar nama depan, disimpan di bidang NameToSelect di tabel NamesToSelect , ditambah beberapa kriteria tambahan (seperti difilter berdasarkan jenis kelamin, tanggal lahir, dll)

Anda dapat melakukannya sebagai berikut

-- @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
sumber
2

Saya mungkin punya solusi untuk ini, meskipun hanya akan bekerja di SQL Server 2008 sejauh yang saya tahu. Saya menemukan bahwa Anda dapat menggunakan konstruktor baris yang dijelaskan di https://stackoverflow.com/a/7285095/894974 untuk bergabung dengan tabel 'fiksi' menggunakan klausa seperti. Kedengarannya lebih kompleks daripada itu, lihat:

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

Ini akan menghasilkan semua pengguna dengan alamat email seperti yang disediakan dalam daftar. Semoga bermanfaat bagi siapa pun. Masalahnya telah mengganggu saya beberapa saat.

Sander
sumber
1
Itu menarik. Namun, perlu diketahui bahwa ini hanya boleh digunakan pada tabel kecil karena pernyataan sejenis tidak dapat menggunakan indeks. Inilah sebabnya mengapa pencarian teks lengkap, walaupun lebih sulit untuk diatur secara awal, adalah pilihan yang lebih baik jika Anda memiliki banyak data.
HLGEM
2

Dimulai dengan 2016, SQL Server menyertakan STRING_SPLIT fungsi . Saya menggunakan SQL Server v17.4 dan saya membuatnya berfungsi:

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

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

Ini berfungsi untuk nilai yang dipisahkan koma

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

Mengevaluasi ke:

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

Jika Anda ingin menggunakan indeks, Anda harus menghilangkan '%'karakter pertama .

David F. Mayer
sumber
1

Di Oracle RBDMS Anda dapat mencapai perilaku ini menggunakan fungsi REGEXP_LIKE .

Kode berikut akan menguji apakah string tiga hadir dalam ekspresi daftar satu | dua | tiga | empat | lima (di mana simbol pipa " | " berarti operasi logika ATAU).

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

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

1 row selected.

Ekspresi sebelumnya setara dengan:

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

Jadi itu akan berhasil.

Di sisi lain, tes berikut akan gagal.

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

no rows selected

Ada beberapa fungsi yang terkait dengan ekspresi reguler (REGEXP_ *) yang tersedia di Oracle sejak versi 10g. Jika Anda seorang pengembang Oracle dan tertarik dengan topik ini, ini harus menjadi awal yang baik Menggunakan Ekspresi Reguler dengan Database Oracle .

abrittaf
sumber
1

Mungkin Anda berpikir kombinasi seperti ini:

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

Jika Anda telah menetapkan indeks teks lengkap untuk tabel target Anda, maka Anda dapat menggunakan alternatif ini:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
Humayoun_Kabir
sumber
Terima kasih. Ini harus menjadi jawaban yang diterima IMO. Tidak semua orang memiliki indeks teks lengkap yang ditentukan (apa pun artinya) Saran pertama Anda berfungsi seperti mantra. Anda bahkan dapat menempatkan wildcard dalam nilai temp table sendiri alih-alih menggabungkan pada LIKE.
The Fool
0

Tidak ada jawaban seperti ini:

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

Di oracle tidak ada masalah.

Hong Van Vit
sumber
0

Di Teradata Anda dapat menggunakan LIKE ANY ('%ABC%','%PQR%','%XYZ%'). Di bawah ini adalah contoh yang menghasilkan hasil yang sama untuk saya

--===========
--  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
sumber
0

Saya tahu ini sangat terlambat, tetapi saya memiliki situasi yang sama. Saya membutuhkan operator "Suka Masuk" untuk serangkaian prosedur tersimpan yang saya miliki, yang menerima banyak parameter dan kemudian menggunakan parameter tersebut untuk mengumpulkan data dari beberapa sistem RDBMS, sehingga tidak ada trik khusus RDBMS yang akan bekerja, namun prosedur tersimpan dan fungsi apa pun akan berjalan di MS SQL Server, jadi kita bisa menggunakan T-SQL untuk fungsi menghasilkan pernyataan SQL lengkap untuk setiap RDBMS, tetapi hasilnya harus cukup RDBMS-independen.

Inilah yang saya buat untuk saat ini untuk mengubah string yang dibatasi (seperti parameter yang masuk ke prosedur tersimpan) menjadi blok SQL. Saya menyebutnya "Lichen" untuk "LIKE IN". Mengerti?

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

Deteksi pembatas mungkin direncanakan, tetapi untuk saat ini defaultnya adalah titik koma sehingga Anda bisa memasukkannya defaultke sana. Mungkin ada bug dalam hal ini. The @leadingAndparameter hanya nilai bit untuk menentukan apakah Anda ingin "DAN" put terkemuka di depan blok sehingga cocok dengan baik dengan MANA penambahan klausa lainnya.

Contoh Penggunaan (dengan pembatas di 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

Akan mengembalikan nvarchar (512) yang berisi:

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

Itu juga akan melewati blok jika input tidak mengandung pembatas:

Contoh Penggunaan (tanpa pembatas di 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

Akan mengembalikan nvarchar (512) yang berisi:

 AND foo.bar LIKE '01%'

Saya akan terus mengerjakan ini, jadi jika saya telah mengabaikan sesuatu (sangat jelas atau sebaliknya), jangan ragu untuk berkomentar atau menjangkau.

NDC
sumber
-3

melakukan hal ini

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

atau

WHERE something + '%' in (select col from table where ....)
Nikolay Hristov
sumber
1
Bagaimana itu akan berhasil? LHS adalah string dengan%, dan karena itu% bukan wildcard
Darius X.