2017-10-10 102 views
1

我有一個變量@a='1,2,3,4'和包含逗號分隔值列B的表。Sql表逗號分隔值包含任何變量值檢查

如何檢查該欄的B值是否包含任何@a變量值?

+2

永遠不要將數據存儲爲逗號分隔的項目,它只會導致很多麻煩。 – jarlh

+0

添加一些示例數據和所需的結果。 –

+0

提供表B的樣本數據 –

回答

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]; 

enter image description here

使用CROSS APPLY我們正在分裂爲每列的值。然後,我們分割過濾值並執行INNER JOIN,以便僅匹配包含在過濾器值中的值的行。之後,我們需要一個DISTINCT,因爲列值可能包含許多來自過濾器的值。

1

一個T-SQL字符串的「分流」是你需要什麼,但我會使用mTVF上面推薦的,因爲它是非常低效並殺死並行。內聯表值函數(iTVF)就是你想要分割字符串的東西。

我會建議使用delimitedSplit8kdelimitedSplit8k_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