Sql表以逗号分隔的值包含任何变量值检查

时间:2017-10-10 07:32:09

标签: sql sql-server csv tsql c#-4.0

我有一个变量@a='1,2,3,4'和一个包含列B的表,其中包含以逗号分隔的值。

如何检查列B值是否包含任何@a变量值?

2 个答案:

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

enter image description here

使用CROSS APPLY我们将拆分每列的值。然后我们分割过滤值并执行INNER JOIN,以便仅匹配具有过滤器值中包含的值的行。之后,我们需要DISTINCT,因为列值可能包含过滤器中的许多值。

答案 1 :(得分:1)

你需要一个t-sql字符串“splitter”,但我 NOT 使用上面推荐的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