Có sự kết hợp nào giữa các lượt THÍCH THÍCH và và IN IN trong SQL không?


340

Trong SQL tôi (đáng buồn thay) thường phải sử dụng các LIKEđiều kiện "" do cơ sở dữ liệu vi phạm gần như mọi quy tắc chuẩn hóa. Tôi không thể thay đổi điều đó ngay bây giờ. Nhưng điều đó không liên quan đến câu hỏi.

Hơn nữa, tôi thường sử dụng các điều kiện như WHERE something in (1,1,2,3,5,8,13,21)để dễ đọc và linh hoạt hơn trong các câu lệnh SQL của mình.

Có cách nào khả thi để kết hợp hai thứ này mà không cần viết các lựa chọn phụ phức tạp không?

Tôi muốn một cái gì đó dễ dàng như WHERE something LIKE ('bla%', '%foo%', 'batz%')thay vì điều này:

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

Tôi đang làm việc với Máy chủ SQl và Oracle tại đây nhưng tôi quan tâm nếu điều này có thể thực hiện được trong bất kỳ RDBMS nào.


1
Bạn phải làm và thích hoặc: VÀ (một cái gì đó THÍCH '% điều%' hoặc một cái gì đó THÍCH '% điều%' hoặc một cái gì đó THÍCH '% điều%')
Cosmic Hawk

Tôi ước chúng tôi có Teradata's like any/ like all: stackoverflow.com/questions/40475982/sql-like-any-vs-like-all . (Đối với hồ sơ, điều này đã được yêu cầu trên ý tưởng Oracle Cộng đồng diễn đàn community.oracle.com/ideas/11592 )
William Robertson

Câu trả lời:


196

Không có sự kết hợp giữa THÍCH & IN trong SQL, ít hơn nhiều trong TSQL (Máy chủ SQL) hoặc PLQuery (Oracle). Một phần lý do cho điều đó là vì Tìm kiếm toàn văn bản (FTS) là giải pháp thay thế được đề xuất.

Cả hai triển khai FTS của Oracle và SQL Server đều hỗ trợ từ khóa CONTAIN, nhưng cú pháp vẫn hơi khác nhau:

Oracle:

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

Máy chủ SQL:

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

Cột bạn đang truy vấn phải được lập chỉ mục toàn văn.

Tài liệu tham khảo:


11
Xin chào, với Oracle, bạn cần xây dựng các chỉ mục văn bản trên các cột bạn muốn áp dụng toán tử "CONTAIN". Tùy thuộc vào khối lượng dữ liệu của bạn, điều này có thể khá dài.
Pierre-Gilles Levallois

18
Với SQL Server (ít nhất là phiên bản 2008), nhận xét của @Pilooz cũng được áp dụng, bạn cần xây dựng các chỉ mục văn bản đầy đủ.
Marcel

Độ dài tối đa là 4000.
ᴍᴀᴛᴛ

59

Nếu bạn muốn làm cho câu lệnh của mình dễ đọc, thì bạn có thể sử dụng REGEXP_LIKE (có sẵn từ phiên bản Oracle 10 trở đi).

Một bảng ví dụ:

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.

Cú pháp ban đầu:

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.

Và một truy vấn tìm kiếm đơn giản với REGEXP_LIKE

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

SOMETH
------
blabla
ofooof
batzzz

3 rows selected.

NHƯNG ...

Tôi sẽ không tự giới thiệu nó do hiệu suất không tốt. Tôi sẽ gắn bó với một số vị từ THÍCH. Vì vậy, các ví dụ chỉ là cho vui.


4
+1 minh họa đẹp về việc sử dụng REGEXP trong 10g. Tôi tò mò, mặc dù, nếu hiệu suất thực sự sẽ tồi tệ hơn nhiều. Cả hai sẽ yêu cầu quét toàn bộ bảng và / hoặc chỉ mục, không?
DCookie

12
Thật. Nhưng các biểu thức thông thường đốt cháy CPU như điên, không phải I / O. Nếu nó tệ hơn và tệ hơn bao nhiêu, tùy thuộc vào danh sách biểu thức của bạn lớn như thế nào và liệu cột có được lập chỉ mục hay không, trong số các cột khác. Đó chỉ là một cảnh báo, để người đăng ban đầu không ngạc nhiên khi anh bắt đầu thực hiện nó.
Rob van Wijk

49

bạn bị mắc kẹt với

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

trừ khi bạn điền vào bảng tạm thời (bao gồm các thẻ hoang dã với dữ liệu) và tham gia như thế này:

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

dùng thử (sử dụng cú pháp 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

ĐẦU RA:

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

(2 row(s) affected)

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

(2 row(s) affected)

Ok, điều này sẽ hoạt động, nhưng nó không đi theo hướng dự định của tôi là làm cho câu lệnh SQL dễ đọc hơn :)
selfawaresoup

10
Trong SQL, bạn sử dụng chỉ mục và hiệu suất. Chỉ sử dụng thụt lề và đặt tên cho khả năng đọc SQL, khi bạn thực hiện các sửa đổi khác cho khả năng đọc chỉ bạn có nguy cơ thay đổi kế hoạch thực hiện (ảnh hưởng đến việc sử dụng chỉ mục và hiệu suất). Nếu không cẩn thận, bạn có thể dễ dàng thay đổi truy vấn đang chạy ngay lập tức thành truy vấn rất chậm bằng cách thực hiện các thay đổi nhỏ.
KM.

Tuyên bố đầu tiên của câu trả lời này là chính - (hầu hết?) Các hệ thống và ngôn ngữ dựa trên SQL không hỗ trợ những gì bạn muốn, không phải không thực hiện các công việc xung quanh. (Trong máy chủ SQL, việc lập chỉ mục Toàn văn bản có giúp được không?)
Philip Kelley

@Philip Kelley, việc lập chỉ mục Toàn văn của SQL Server có thể thực hiện được LIKE 'bla%' , trong mã ví dụ của OP không? hoặc chỉ có thể thực hiện LIKE '%bla%'tìm kiếm?
KM.

Tôi thực sự không biết, tôi chưa bao giờ sử dụng lập chỉ mục FT. Tôi đã ném nó như một ví dụ về một công việc có thể có trong sản phẩm. Đối với những gì anh ấy đang làm (A hoặc B hoặc C), tôi nghi ngờ nó không làm điều đó, tôi khá tự tin rằng sẽ mất rất nhiều nỗ lực để xác định điều này và biết rằng nó nằm ngoài phạm vi câu hỏi ban đầu của anh ấy (không SQL làm điều đó tự nhiên).
Philip Kelley

20

Với PostgreSQL có ANYhoặc ALLhình thức:

WHERE col LIKE ANY( subselect )

hoặc là

WHERE col LIKE ALL( subselect )

trong đó subselect trả về chính xác một cột dữ liệu.


1
LIKE ANYLIKE ALLphổ biến cho tất cả các phương ngữ SQL, tức là một phần của ngôn ngữ cốt lõi, hoặc cụ thể cho một phương ngữ?
Assad Ebrahim

1
@AssadEbrahim, không có họ là cụ thể. Oracle có = ANYhoặc <> ALLnhưng nó chỉ hoạt động trong SQL, không phải trong PLQuery chẳng hạn.
Benoit

Tôi nghĩ đây là cú pháp chuẩn (nhưng không nhiều DBMS đã triển khai nó)
ypercubeᵀᴹ 15/03/2017

Để biết các postgres, hãy xem stackoverflow.com/questions/2245536/ trên
rogerdpack

13

Một giải pháp khác, nên hoạt động trên bất kỳ RDBMS nào:

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)

1
Nhưng nó xấu hơn một tập hợp các câu lệnh OR
Fandango68

1
@ Fandango68, nhưng sự kết hợp của các lựa chọn có thể được thay thế bằng một nguồn mẫu khác như bảng, chế độ xem, v.v.
mik

10

Tôi sẽ đề nghị sử dụng chức năng người dùng TableValue nếu bạn muốn gói gọn các kỹ thuật bảng trong Tham gia hoặc bảng tạm thời được hiển thị ở trên. Điều này sẽ cho phép nó đọc rõ hơn một chút.

Sau khi sử dụng chức năng phân tách được xác định tại: http://www.logiclabz.com/sql-server/split-feft-in-sql-server-to-break-comma-separated-strings-into-table.aspx

chúng ta có thể viết như sau dựa trên một bảng mà tôi đã tạo được gọi là "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.

Đầu ra

1 âm trầm
2 Pike
7 Angler
8 Walleye

1
Một hàng sẽ được nhân đôi nếu khớp với nhiều điều kiện cùng một lúc.
mik

7

Một cách tiếp cận sẽ là lưu trữ các điều kiện trong một bảng tạm thời (hoặc biến bảng trong SQL Server) và tham gia vào đó như sau:

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

Một hàng sẽ được nhân đôi nếu khớp với nhiều điều kiện cùng một lúc.
mik

7

Sử dụng một tham gia bên trong thay thế:

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

1
Chà, đó chính xác là những gì tôi muốn tránh. Mặc dù nó hoạt động.
selfawaresoup

Tại sao phải tránh giải pháp này? Nó hoạt động nhanh như giải pháp được chấp nhận, và cũng linh hoạt.
Phil Factor

3
@PhilFactor Giải pháp này có thể tạo các hàng trùng lặp.
Jakub Kania

5

Tôi đang làm việc với Máy chủ SQl và Oracle tại đây nhưng tôi quan tâm nếu điều này có thể thực hiện được trong bất kỳ RDBMS nào.

Teradata hỗ trợ cú pháp THÍCH TẤT CẢ / BẤT K ::

TẤT CẢ mọi chuỗi trong danh sách.
MỌI chuỗi bất kỳ trong danh sách.

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

BIÊN TẬP:

jOOQ phiên bản 3.12.0 hỗ trợ cú pháp đó:

Thêm tổng hợp [KHÔNG] THÍCH BẤT K and và [KHÔNG] THÍCH TẤT CẢ toán tử

Rất nhiều lần, người dùng SQL muốn có thể kết hợp các vị từ THÍCH và IN, như trong:

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

Cách giải quyết là mở rộng thủ công vị ngữ thành tương đương

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

jOOQ có thể hỗ trợ một vị từ tổng hợp như vậy ra khỏi hộp.


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


Bông tuyết cũng hỗ trợ THÍCH BẤT K / / THÍCH TẤT CẢ phù hợp:

THÍCH BẤT K / / TẤT CẢ

Cho phép khớp chuỗi phân biệt chữ hoa chữ thường dựa trên so sánh với một hoặc nhiều mẫu.

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

Thí dụ:

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

4

bạn thậm chí có thể thử cái này

Chức năng

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

Truy vấn

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

Tôi có một giải pháp đơn giản, ít nhất là hoạt động trong postgresql , sử dụng like anytheo sau là danh sách regex. Dưới đây là một ví dụ, xem xét việc xác định một số loại kháng sinh trong danh sách:

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

3

Tôi cũng đã tự hỏi cho một cái gì đó như thế. Tôi chỉ thử nghiệm sử dụng một sự kết hợp của SUBSTRINGINvà nó là một giải pháp hiệu quả cho các loại vấn đề. Hãy thử truy vấn dưới đây:

Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')

1
Một vấn đề với cách tiếp cận này là bạn mất khả năng sử dụng một chỉ mục trên t1. Một cái gì đó nếu nó tồn tại ..
ShoeLace

1
điều này sẽ không bao giờ tìm thấy 'batz'
mik

3

Trong Oracle, bạn có thể sử dụng một bộ sưu tập theo cách sau:

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

Ở đây tôi đã sử dụng một loại bộ sưu tập được xác định trước ku$_vcnt, nhưng bạn có thể khai báo loại của riêng bạn như thế này:

CREATE TYPE my_collection AS TABLE OF VARCHAR2(4000);

2

Đối với Sql Server, bạn có thể sử dụng SQL động.

Hầu hết thời gian trong các tình huống như vậy, bạn có tham số mệnh đề IN dựa trên một số dữ liệu từ cơ sở dữ liệu.

Ví dụ dưới đây là một chút "bắt buộc", nhưng điều này có thể phù hợp với các trường hợp thực tế khác nhau được tìm thấy trong cơ sở dữ liệu cũ.

Giả sử bạn có bảng Người có tên người được lưu trữ trong một trường PersonName là FirstName + '' + LastName. Bạn cần chọn tất cả những người từ danh sách tên, được lưu trữ trong trường NameToSelect trong bảng NameToSelect , cộng với một số tiêu chí bổ sung (như được lọc theo giới tính, ngày sinh, v.v.)

Bạn có thể làm như sau

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

Tôi có thể có một giải pháp cho việc này, mặc dù nó sẽ chỉ hoạt động trong SQL Server 2008 theo như tôi biết. Tôi phát hiện ra rằng bạn có thể sử dụng hàm tạo hàng được mô tả trong https://stackoverflow.com/a/7285095/894974 để tham gia bảng 'hư cấu' bằng cách sử dụng mệnh đề like. Nghe có vẻ phức tạp hơn, nó nhìn:

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

Điều này sẽ dẫn đến tất cả người dùng có một địa chỉ email giống như những người được cung cấp trong danh sách. Hy vọng nó sẽ được sử dụng cho bất cứ ai. Vấn đề đã làm phiền tôi một thời gian.


1
Nó thật thú vị. Tuy nhiên, lưu ý rằng điều này chỉ nên được sử dụng trên bảng smal vì câu lệnh tương tự không thể sử dụng các chỉ mục. Đây là lý do tại sao tìm kiếm toàn văn bản, trong khi khó thiết lập hơn, là lựa chọn tốt hơn nếu bạn có nhiều dữ liệu.
HLGEM

2

Bắt đầu từ năm 2016, SQL Server bao gồm một STRING_SPLIT chức năng . Tôi đang sử dụng SQL Server v17.4 và tôi đã làm việc này cho tôi:

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

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


1

Điều này hoạt động cho các giá trị được phân tách bằng dấu phẩy

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

Đánh giá để:

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

Nếu bạn muốn nó sử dụng các chỉ mục, bạn phải bỏ qua '%'ký tự đầu tiên .


1

Trong Oracle RBDMS, bạn có thể đạt được hành vi này bằng cách sử dụng hàm REGEXP_LIKE .

Đoạn mã sau sẽ kiểm tra xem chuỗi ba có trong biểu thức danh sách một | hai | ba | bốn | năm (trong đó ký hiệu " | " ống có nghĩa là hoạt động logic HOẶC).

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

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

1 row selected.

Biểu thức trước tương đương với:

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

Vậy là nó sẽ thành công.

Mặt khác, bài kiểm tra sau sẽ thất bại.

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

no rows selected

Có một số hàm liên quan đến biểu thức chính quy (REGEXP_ *) có sẵn trong Oracle kể từ phiên bản 10g. Nếu bạn là một nhà phát triển của Oracle và quan tâm đến chủ đề này thì đây sẽ là một khởi đầu tốt khi sử dụng Biểu thức chính quy với Cơ sở dữ liệu Oracle .


1

Có thể bạn nghĩ rằng sự kết hợp như thế này:

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

Nếu bạn đã xác định chỉ mục văn bản đầy đủ cho bảng mục tiêu của mình thì bạn có thể sử dụng phương án này:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')

Cảm ơn bạn. Đây phải là câu trả lời được chấp nhận IMO. Không phải ai cũng có một chỉ mục toàn văn được xác định (bất kể điều đó có nghĩa là gì) Những đề xuất đầu tiên của bạn hoạt động như một cơ duyên. Bạn thậm chí có thể đặt các ký tự đại diện trong các giá trị bảng tạm thời thay vì ghép nối trên THÍCH.
The Fool

0

Không có câu trả lời như thế này:

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

Trong nhà tiên tri không có vấn đề.


0

Trong Teradata bạn có thể sử dụng LIKE ANY ('%ABC%','%PQR%','%XYZ%'). Dưới đây là một ví dụ đã tạo ra kết quả tương tự cho tôi

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

0

Tôi biết điều này là rất muộn, nhưng tôi đã có một tình huống tương tự. Tôi cần một toán tử "Thích trong" cho một tập hợp các thủ tục được lưu trữ mà tôi có, chấp nhận nhiều tham số và sau đó sử dụng các tham số đó để tổng hợp dữ liệu từ nhiều hệ thống RDBMS, do đó không có thủ thuật cụ thể nào của RDBMS hoạt động, tuy nhiên thủ tục được lưu trữ và bất kỳ chức năng nào sẽ chạy trên MS SQL Server, vì vậy chúng tôi có thể sử dụng T-SQL cho chức năng tạo các câu lệnh SQL đầy đủ cho mỗi RDBMS, nhưng đầu ra cần phải độc lập với RDBMS.

Đây là những gì tôi nghĩ ra lúc này để biến một chuỗi được phân tách (chẳng hạn như một tham số đi vào một thủ tục được lưu trữ) thành một khối SQL. Tôi gọi nó là "Địa y" cho "THÍCH VÀO". Hiểu rồi?

Địa y

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

Việc phát hiện dấu phân cách có thể được lên kế hoạch, nhưng bây giờ nó mặc định là dấu chấm phẩy để bạn có thể đặt defaultvào đó. Có lẽ có lỗi trong này. Các @leadingAndthông số chỉ là một giá trị bit để xác định xem bạn muốn có một "VÀ" đặt hàng đầu ở phía trước của khối sao cho nó vừa độc đáo với mệnh đề WHERE bổ sung khác.

Sử dụng ví dụ (với dấu phân cách trong 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

Sẽ trả về một nvarchar (512) có chứa:

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

Nó cũng sẽ bỏ qua khối nếu đầu vào không chứa dấu phân cách:

Sử dụng ví dụ (không có dấu phân cách trong 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

Sẽ trả về một nvarchar (512) có chứa:

 AND foo.bar LIKE '01%'

Tôi sẽ tiếp tục làm việc này, vì vậy nếu tôi bỏ qua điều gì đó (rõ ràng là rõ ràng hoặc nói cách khác) xin vui lòng bình luận hoặc tiếp cận.


-3

làm cái này

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

hoặc là

WHERE something + '%' in (select col from table where ....)

1
Làm thế nào mà đi làm? LHS là một chuỗi có% và do đó% không phải là ký tự đại diện
Darius X.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.