我有一个变量@a='1,2,3,4'
和一个包含列B
的表,其中包含以逗号分隔的值。
如何检查列B
值是否包含任何@a
变量值?
答案 0 :(得分:1)
您需要实现一个用于拆分值的函数。有很多变化,你可以使用它:
CREATE FUNCTION [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder](@List nvarchar(max), @Delimiter nvarchar(10) = ',')
RETURNS @result TABLE
(
[Value] nvarchar(max),
[SortOrder] bigint NOT NULL
)
AS
BEGIN
IF @Delimiter is null
BEGIN
SET @Delimiter = ','
END
DECLARE @XML xml = N'<r><![CDATA[' + REPLACE(@List, @Delimiter, ']]></r><r><![CDATA[') + ']]></r>'
DECLARE @BufTable TABLE (Value nvarchar(max), SortOrder bigint NOT NULL IDENTITY(1, 1) PRIMARY KEY)
INSERT INTO @BufTable (Value)
SELECT Tbl.Col.value('.', 'nvarchar(max)')
FROM @xml.nodes('//r') Tbl(Col)
OPTION (OPTIMIZE FOR (@xml = NULL))
INSERT INTO @result (Value, SortOrder)
SELECT Value, SortOrder
FROM @BufTable
RETURN
END
有这样的功能,很简单:
DECLARE @DataSource TABLE
(
[column] VARCHAR(1024)
);
DECLARE @column VARCHAR(1024) = '1,2,3,4';
INSERT INTO @DataSource ([column])
VALUES ('100,200,300')
,('100,1,500')
,('1,2,3,500')
,('200')
,('33,32,31,4,30');
SELECT DISTINCT [column]
FROM @DataSource
CROSS APPLY [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder] ([column], ',') DSV
INNER JOIN [dbo].[fn_Analysis_ConvertCsvListToNVarCharTableWithOrder] (@column, ',') FV
ON DSV.[Value] = FV.[Value];
使用CROSS APPLY
我们将拆分每列的值。然后我们分割过滤值并执行INNER JOIN
,以便仅匹配具有过滤器值中包含的值的行。之后,我们需要DISTINCT
,因为列值可能包含过滤器中的许多值。
答案 1 :(得分:1)
你需要一个t-sql字符串“splitter”,但我 NOT 使用上面推荐的mTVF,因为它非常效率低并且会杀死并行性。内联表值函数(iTVF)是分割字符串所需的。
我建议使用delimitedSplit8k或delimitedSplit8k_lead,这样可以提高约30-90倍;或STRING_SPLIT如果您使用的是SQL 2016+,并且只需要几百倍的值。请注意此性能测试:
-- sample data
declare @rows int = 10000;
if object_id('tempdb..#strings') is not null drop table #strings;
select top (@rows)
someid = identity(int,1,1),
somestring = replace(right(left(cast(newid() as varchar(36)), 27),21),'-',',')
into #strings
from sys.all_columns a, sys.all_columns b;
-- Performance test
set nocount on;
print 'fn_Analysis_ConvertCsvListToNVarCharTableWithOrder'+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @item varchar(10);
select @item = [value]
from #strings t
cross apply dbo.fn_Analysis_ConvertCsvListToNVarCharTableWithOrder(t.somestring,',');
print datediff(ms,@st,getdate());
go 5
print 'delimitedSplit8K (serial)'+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @item varchar(10);
select @item = item
from #strings t
cross apply dbo.DelimitedSplit8K(t.somestring,',')
option (maxdop 1);
print datediff(ms,@st,getdate());
go 5
print 'delimitedSplit8K (parallel)'+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @item varchar(10);
select @item = item
from #strings t
cross apply dbo.DelimitedSplit8K(t.somestring,',')
option (recompile, querytraceon 8649);
print datediff(ms,@st,getdate());
go 5
<强>结果
fn_Analysis_ConvertCsvListToNVarCharTableWithOrder
--------------------------------------------------
Beginning execution loop
4183
4274
4536
4294
4406
Batch execution completed 5 times.
delimitedSplit8K (serial)
--------------------------------------------------
Beginning execution loop
50
50
50
54
53
Batch execution completed 5 times.
delimitedSplit8K (parallel)
--------------------------------------------------
Beginning execution loop
133
134
133
140
136
Batch execution completed 5 times.
如何用来解决问题
declare @sometable table(someid int identity, someNbr tinyint);
insert @sometable values (1),(3),(6),(12),(7),(15),(19);
declare @searchstring varchar(1000) = '1,2,3,4,19';
select someid, someNbr
from @sometable t
cross apply dbo.DelimitedSplit8K(@searchstring,',') s
where t.someNbr = s.Item;
<强>结果
someid someNbr
----------- -------
1 1
2 3
7 19