【问题标题】:How to filter records when filter is a comma separated list of values当过滤器是逗号分隔的值列表时如何过滤记录
【发布时间】:2013-06-27 10:03:20
【问题描述】:

我有一个表,其中有一列包含一串逗号分隔值 (CSV)。

例如VALUE1、VALUE2、VALUE3

作为过滤器传入的是另一组 CSV。

例如VALUE2,VALUE3

所以在上面的例子中,查询应该返回任何过滤值在 CSV 列中的记录。

示例

declare @table table
(
    rownum int,
    csv nvarchar(300)
)

insert into @table values (1,'VALUE1, VALUE2, VALUE3')
insert into @table values (2,'VALUE1, VALUE2')
insert into @table values (3,'VALUE1, VALUE3')
insert into @table values (4,'VALUE3, VALUE4')
insert into @table values (5,'VALUE1, VALUE2, VALUE3')
insert into @table values (6,'VALUE3, VALUE4, VALUE2')
insert into @table values (7,'VALUE3')

declare @Filter nvarchar(50)

set @Filter = 'VALUE1,VALUE2'

select * from @table

因此,在上面的示例中,第 1、2、3、5 和 6 行应该由查询返回,因为它们都包含 VALUE1 或 VALUE2。

【问题讨论】:

  • 只是为了确定,在您的描述之后,它应该返回所有行,对吗?第 4 行有 VALUE2 位于过滤器上,第 7 行也有
  • 对不起,我的错,我忘记更新示例代码了。
  • 好的。我发布的解决方案考虑到了这一点:)它会正常工作。

标签: sql-server tsql


【解决方案1】:

如果我很好理解,这将解决它:

您创建一个函数来进行拆分:

CREATE FUNCTION [dbo].[ufn_CSVToTable] ( @StringInput VARCHAR(8000), @Delimiter nvarchar(1))
RETURNS @OutputTable TABLE ( [String] VARCHAR(10) )
AS
BEGIN

    DECLARE @String    VARCHAR(10)

    WHILE LEN(@StringInput) > 0
    BEGIN
        SET @String      = LEFT(@StringInput, 
                                ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput) - 1, -1),
                                LEN(@StringInput)))
        SET @StringInput = SUBSTRING(@StringInput,
                                     ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput), 0),
                                     LEN(@StringInput)) + 1, LEN(@StringInput))

        INSERT INTO @OutputTable ( [String] )
        VALUES ( @String )
    END

    RETURN
END
GO

那么你可以这样做:

declare @table table
(
    rownum int,
    csv nvarchar(300)
)

insert into @table values (1,'VALUE1, VALUE2, VALUE3')
insert into @table values (2,'VALUE1, VALUE2')
insert into @table values (3,'VALUE1, VALUE3')
insert into @table values (4,'VALUE2, VALUE3')
insert into @table values (5,'VALUE1, VALUE2, VALUE3')
insert into @table values (6,'VALUE3, VALUE1, VALUE2')
insert into @table values (7,'VALUE2, VALUE1')

declare @Filter nvarchar(50)

set @Filter = 'VALUE3,VALUE4'

select * from @table
SELECT * INTO #FilterTable FROM ufn_CSVToTable(@Filter, ',')
SELECT * FROM #FilterTable
select * from @table where EXISTS(SELECT String FROM #FilterTable WHERE csv like '%' + String + '%')
DROP TABLE #FilterTable

我正在考虑描述“返回包含过滤器中任何计算的任何行”

【讨论】:

    【解决方案2】:

    您可以使用 PatIndex 找出该字段中的模式。像下面这样:

    SELECT * FROM @TABLE WHERE PATINDEX('%'+@FILTER+'%',CSV)>0
    

    【讨论】:

    • 或者您可以使用 contains ,但这仅在您的表格上有全文索引时才有效。 select * from @table where CONTAINS(csv, @Filter)
    • 不起作用 - 您可能有不同顺序的值,例如“VAL1,VAL2”与“VAL2,VAL1”,或包含空格,例如“VAL1,VAL2”与“VAL1,VAL2”等等等等。
    【解决方案3】:

    现在呢?我根本没有使用任何用户定义的函数。

    declare @table table
    (
        rownum int,
        csv nvarchar(300)
    )
    
    insert into @table values (1,'VALUE1,VALUE2,VALUE3')
    insert into @table values (2,'VALUE1,VALUE2')
    insert into @table values (3,'VALUE1,VALUE3')
    insert into @table values (4,'VALUE2,VALUE3')
    insert into @table values (5,'VALUE1,VALUE2,VALUE3')
    insert into @table values (6,'VALUE3,VALUE1,VALUE2')
    insert into @table values (7,'VALUE2,VALUE1')
    
    DECLARE @FILTER VARCHAR(50)
    DECLARE @IN VARCHAR(MAX)
    SET @FILTER='VALUE1,VALUE2'
    SET @IN=REPLACE(@FILTER,',','%')
    SET @IN='%'+@IN+'%'
    SELECT @IN
    SELECT * FROM @table WHERE PATINDEX(@IN,RTRIM(LTRIM(CSV))) >0
    

    【讨论】:

    • 谢谢,但这错过了第 3 行和第 6 行。
    【解决方案4】:

    试试这个 -

    DECLARE @table TABLE (rownum INT, csv NVARCHAR(300))
    
    INSERT INTO @table 
    VALUES 
           (1,'VALUE1, VALUE2, VALUE3')
         , (2,'VALUE1, VALUE2')
         , (3,'VALUE1, VALUE3')
         , (4,'VALUE2, VALUE3')
         , (5,'VALUE1, VALUE2, VALUE3')
         , (6,'VALUE3, VALUE1, VALUE2')
         , (7,'VALUE2, VALUE1')
    
    DECLARE @Filter NVARCHAR(50)
    SELECT @Filter = 'VALUE1,VALUE2'
    
    ;WITH cte AS 
    (
         SELECT token = SUBSTRING(
              t.string
            , n.number + 1
            , ABS(CHARINDEX(',', t.string, n.number + 1) - n.number - 1))
         FROM ( SELECT string = ',' + @Filter ) t
         CROSS JOIN [master].dbo.spt_values n
         WHERE n.[type] = 'p'
             AND n.number <= LEN(t.string)
             AND SUBSTRING(t.string, n.number, 1) = ','
    )
    SELECT DISTINCT rownum, csv
    FROM cte
    JOIN @table ON PATINDEX('%'+ token +'%', CSV) = 0
    

    【讨论】:

    • 也许我误解了这个问题。
    • 谢谢,但这似乎不起作用。它返回行; 3、4、4、6、7、7
    猜你喜欢
    • 2022-01-25
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 2015-01-06
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多