我的存储过程接收到一个以逗号分隔的字符串的参数:
DECLARE @Account AS VARCHAR(200)
SET @Account = 'SA,A'
我需要从中做出这样的声明:
WHERE Account IN ('SA', 'A')
这样做的最佳做法是什么?
我的存储过程接收到一个以逗号分隔的字符串的参数:
DECLARE @Account AS VARCHAR(200)
SET @Account = 'SA,A'
我需要从中做出这样的声明:
WHERE Account IN ('SA', 'A')
这样做的最佳做法是什么?
创建这个函数(sqlserver 2005+)
CREATE function [dbo].[f_split]
(
@param nvarchar(max),
@delimiter char(1)
)
returns @t table (val nvarchar(max), seq int)
as
begin
set @param += @delimiter
;with a as
(
select cast(1 as bigint) f, charindex(@delimiter, @param) t, 1 seq
union all
select t + 1, charindex(@delimiter, @param, t + 1), seq + 1
from a
where charindex(@delimiter, @param, t + 1) > 0
)
insert @t
select substring(@param, f, t - f), seq from a
option (maxrecursion 0)
return
end
使用这个语句
SELECT *
FROM yourtable
WHERE account in (SELECT val FROM dbo.f_split(@account, ','))
将我的拆分功能与 XML 拆分进行比较:
测试数据:
select top 100000 cast(a.number as varchar(10))+','+a.type +','+ cast(a.status as varchar(9))+','+cast(b.number as varchar(10))+','+b.type +','+ cast(b.status as varchar(9)) txt into a
from master..spt_values a cross join master..spt_values b
XML:
SELECT count(t.c.value('.', 'VARCHAR(20)'))
FROM (
SELECT top 100000 x = CAST('<t>' +
REPLACE(txt, ',', '</t><t>') + '</t>' AS XML)
from a
) a
CROSS APPLY x.nodes('/t') t(c)
Elapsed time: 1:21 seconds
f_split:
select count(*) from a cross apply clausens_base.dbo.f_split(a.txt, ',')
Elapsed time: 43 seconds
这会随着运行而变化,但你明白了
试试这个——
DDL:
CREATE TABLE dbo.Table1 (
[EmpId] INT
, [FirstName] VARCHAR(7)
, [LastName] VARCHAR(10)
, [domain] VARCHAR(6)
, [Vertical] VARCHAR(10)
, [Account] VARCHAR(50)
, [City] VARCHAR(50)
)
INSERT INTO dbo.Table1 ([EmpId], [FirstName], [LastName], [Vertical], [Account], [domain], [City])
VALUES
(345, 'Priya', 'Palanisamy', 'DotNet', 'LS', 'Abbott', 'Chennai'),
(346, 'Kavitha', 'Amirtharaj', 'DotNet', 'CG', 'Diageo', 'Chennai'),
(647, 'Kala', 'Haribabu', 'DotNet', 'DotNet', 'IMS', 'Chennai')
询问:
DECLARE @Account VARCHAR(200)
SELECT @Account = 'CG,LS'
SELECT *
FROM Table1
WHERE [Vertical] = 'DotNet' AND (ISNULL(@Account, '') = '' OR Account IN (
SELECT t.c.value('.', 'VARCHAR(20)')
FROM (
SELECT x = CAST('<t>' +
REPLACE(@Account, ',', '</t><t>') + '</t>' AS XML)
) a
CROSS APPLY x.nodes('/t') t(c)
))
输出:
扩展统计:
SSMS 设置统计时间 + IO:
XML:
(3720 row(s) affected)
Table 'temp'. Scan count 3, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 187 ms, elapsed time = 242 ms.
热电偶:
(3720 row(s) affected)
Table '#BF78F425'. Scan count 360, logical reads 360, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'temp'. Scan count 1, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 281 ms, elapsed time = 335 ms.
最有效的方法是使用 CLR 函数来拆分字符串。有关示例和性能比较,请参阅本文
SQL Server 2016+ 提供了此处描述的 String_Split:https://www.sqlshack.com/the-string-split-function-in-sql-server/,它非常适合我的目的并且易于使用,例如像这样:
declare @InClauesQueryString nvarchar(100) = '1,2';
declare @exampleTable table(ID int,Val nvarchar(100));
INSERT INTO @exampleTable (ID, Val) VALUES (1,'test1');
INSERT INTO @exampleTable (ID, Val) VALUES (2,'test2');
select * from @exampleTable where id in (select * from string_split(@InClauesQueryString,','));