使用带有SQL变量的WHERE IN子句搜索包括SQL中的范围在内的值的列表?

时间:2019-03-30 07:39:51

标签: sql sql-server tsql

我正在尝试使用SQL变量值列表(包括范围)来实现搜索功能。感谢所有指向正确方法的指南/链接。

下面是数据集:

CREATE TABLE [dbo].[Books]
(
    [ID] [NCHAR](10) NOT NULL,
    [AUTHCODE] [NCHAR](10) NULL,
    [TITLE] [NCHAR](10) NULL
) ON [PRIMARY]
GO

INSERT [dbo].[Books] ([ID], [AUTHCODE], [TITLE]) 
VALUES (N'1', N'nk', N'Book1'), 
       (N'2', N'an', N'Book2'),
       (N'3', N'mn', N'Book3'),
       (N'4', N'ra', N'Book4'),
       (N'5', N'kd', N'Book5'),
       (N'6', N'nk', N'Book6'),
       (N'7', N'an', N'Book7'),
       (N'8', N'ra', N'Book8'),
       (N'9', N'kd', N'Book9'),
       (N'10', N'mn', N'Book10    ')
GO

下面,我尝试使用SQL IN子句进行过滤,但这不会返回所需的结果。

select * from books

declare @List1 varchar(max) = '2,4,6,7,8,9' --simple list

select * 
from books
where id in (@List1)

declare @List2 varchar(max) = '2,4-7,9' --list with range

select * 
from books
where id in (@List2)

2 个答案:

答案 0 :(得分:2)

您不能直接将字符串用作列表,但是如果确实需要将过滤参数作为字符串传递,则可以使用STRING_SPLIT (Transact-SQL)

declare @list varchar(max) = '2,4,6-8,9'
declare @filter table (id1 int, id2 int)

insert into @filter (id1,id2)
select
    case when b.pos > 0 then left(a.[value], pos - 1) else a.[value] end as id1,
    case when b.pos > 0 then right(a.[value], len(a.[value]) - pos) else a.[value] end as id2
from string_split(@list, ',') as a
    cross apply (select charindex('-', a.[value]) as pos) as b

select *
from [dbo].[Books] as b
where
    exists (select * from @filter as tt where b.id between tt.id1 and tt.id2)

另外,将过滤器作为json和OPENJSON (Transact-SQL)传递可能是一个主意,这样您就可以简化解析部分:

declare @list varchar(max) = '[2,4,[6,8],9]'

select
    case when a.[type] = 4 then json_value(a.[value], '$[0]') else a.[value] end,
    case when a.[type] = 4 then json_value(a.[value], '$[1]') else a.[value] end
from openjson(@list) as a

当然,以上所有内容仅在拥有Sql Server 2016或更高版本的情况下适用

答案 1 :(得分:1)

IN() 运算符确定指定的值是否匹配子查询列表中的任何值。不是字符串,而是您在做什么。

您可以尝试执行的操作

DECLARE @List1 AS TABLE (ID INT); 

INSERT INTO @List1 
SELECT 2 UNION SELECT 4 UNION SELECT 6 UNION
SELECT 7 UNION SELECT 8 UNION SELECT 9;

SELECT *
FROM Books
WHERE ID IN (SELECT ID FROM @List1);

DECLARE @List2 As TABLE (AFrom INT, ATo INT);

INSERT INTO @List2
SELECT 2, 4 UNION SELECT 7, 9;

SELECT *
FROM Books B CROSS APPLY @List2 L
WHERE B.ID BETWEEN L.AFrom AND L.ATo;

Live Demo