逗号分隔的SQL字符串需要分隔

时间:2010-02-22 17:03:11

标签: sql sql-server sql-server-2005 tsql

我有来自.net应用程序的这个字符串 A,B,C,d,E,F,

我想写一个像

这样的sql select语句
set @string = 'A,B,C,D,E,F'

select * from tbl_test 
where tbl_test.code in (@string)

这在t-SQL中不起作用,因为它使用@string作为一个字符串而不是将值分开。我有什么方法可以做到这一点吗?

11 个答案:

答案 0 :(得分:2)

3个选项

  1. 使用正则表达式将“,”替换为“','”,使其成为正确的('A','B'...)列表
  2. 将列表转换为XML,然后在SELECT
  3. 中解析XML
  4. Write a SPLIT function将逗号分隔的列表转换为表格

答案 1 :(得分:2)

很常见的问题!你想要的是一个表值函数。

但是不要通过写自己来重新发明轮子,我通过Google搜索sql split找到了几十个。这是来自微软的一个:

http://code.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=StringArrayInput

我过去常常使用动态SQL,但这意味着我必须挖掘代码并将其复制到每个新应用中。现在我甚至不用考虑它。

答案 2 :(得分:1)

动态IN子句意味着:

  1. 将逗号分隔列表转换为临时表以加入
  2. 使用动态SQL(EXEC或EXEC sp_executesql)
  3. 动态SQL示例


    DECLARE @SQL NVARCHAR(4000)
    
        SET @SQL = 'SELECT * FROM tbl_test t
                     WHERE t.code IN (@string_param)
    
    BEGIN
    
      EXEC sp_executesql @SQL N'@string_param VARCHAR(100)', @string
    
    END
    

    请注意sp_executesql是2005+,并且首选,因为它会缓存查询计划。请阅读The Curse and Blessings of Dynamic SQL了解更多详情,但请注意SQL injection attacks

答案 3 :(得分:1)

创建一个用户定义的函数,它将字符串作为输入并返回一个表:

create function [dbo].[f_SplitString] (@str as varchar (1000))
returns @t table (value varchar (50))
etc...

然后调整您的Select语句:

select * from tbl_test 
where tbl_test.code in (select value from f_SplitString(@string))

答案 4 :(得分:1)

它认为最简单的方法就是动态SQL生成:

// assuming select is a SqlCommand
string[] values = "A,B,C,D,E,F".Split(',');
StringBuilder query = new StringBuilder();
query.Append("select * from tbl_test where tbl_test.code in (");
int i = 0;
foreach (string value in values) {
    string paramName = "@p" + i++;
    query.Append(paramName);
    select.Parameters.AddWithValue(paramName, value);
}
query.Append(")");
select.CommandText = query.ToString();

// and then execute the select Command

答案 5 :(得分:1)

这是一个函数,它将分隔的String作为一组行返回

set @string = 'A,B,C,D,E,F'      

select * from tbl_test       
where tbl_test.code in (select r from ftDelimitedAsTable(',',@string )    


  --/*----------------------------------------------------------------
    Create     FUNCTION [dbo].[ftDelimitedAsTable](@dlm char, @string varchar(8000))
    RETURNS 
    --------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------
    declare @dlm  char, @string varchar(1000)
    set @dlm=','; set @string='t1,t2,t3';
    -- tHIS FUNCION RETUNRS IN THE ASCENDING ORDER
    -- 19TH Apr 06
    ------------------------------------------------------------------------*/
    --declare
        @table_var TABLE 
        (id int identity(1,1),
            r varchar(1000) 
         )
    AS
    BEGIN
    -- a.p --
    --Modified  18th Nov. 04

        declare @n int,@i int
        set @n=dbo.fnCountChars(@dlm,@string)+1
        SET @I =1
        while @I <= @N
            begin

                --print '@i='+convert(varchar,@i)+ ' AND INSERTING'
                insert @table_var
                    select dbo.fsDelimitedString(@dlm,@string,@i)
                set @I= @I+1

            end
    --PRINT '*************** ALL DONE'
        if @n =1 insert @TABLE_VAR VALUES(@STRING)
    --select * from @table_var
        delete  from @table_var where r=''
        return
    END


USE [QuickPickDBStaging]
GO
/****** Object:  UserDefinedFunction [dbo].[fsDelimitedString]    Script Date: 02/22/2010 12:31:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Create function [dbo].[fsDelimitedString](
            @DelimiterStr varchar(100)
            ,@str varchar(4000)
            ,@pos int=1)
 returns varchar(4000)
as
/*
AP -- Dec 2003
Declare @DelimiterStr varchar(4000),@str varchar(4000) ,@pos int
set @delimiterStr = '-'
set @pos=10
set @str ='wd-1-22-333-4444-55555-666666-q-9'
*/
Begin
declare @rx varchar(4000)
set @rx=''; set @pos=@pos-1
IF DBO.fnCountChars(@DelimiterStr,@str) > 0 
    Begin
        if dbo.fnCountChars(@delimiterStr,@str) < @pos
        begin
            set @rx= null
            goto nulls
        end
        declare @i1 int,@tPos int,@ix int

        set @ix=1
        set @tPos=0
        while @tpos <> @pos
        Begin
            set @ix=charindex(@DelimiterStr,@str,@ix+1)
            if @ix > 0 set @tpos=@tpos+1
        end
        set @i1= charindex(@DelimiterStr,@str,@ix+1)
        if @i1=0 
                set @rx=substring(@str,@ix+1,len(@str)-@ix)
        else
            begin
                if @ix=1  
                    set @rx=substring(@str,@ix,@i1-@ix)
                else
                    set @rx= substring(@str,    @ix+1,@i1-@ix-1)        
            end
    --  'print 'ix='+convert(varchar,@ix)+' @i1='+convert(varchar,@i1)+' @rx='+@rx
        RETURN @RX
    end
nulls:  
    RETURN  @rx
end

答案 6 :(得分:1)

您有几种选择:

  • 如果你没问题,只需在调用SQL之前动态编写 SQL语句IN语句
  • 中的值数量有限制
  • 使用表值UDF 拆分字符串并返回表格。然后,您的查询将使用IN或更好的JOIN语句(在其他实施中,我赞成SQL User Defined Function to Parse a Delimited String)。

你的代码是:

select     tbl_test.*
from       tbl_test 
inner join fn_ParseText2Table(@string) x
       on  tbl_test.code = x.txt_value 
  • 由于您使用的是SQL Server 2005,因此您可以编写 CLR表值UDF ,它可以执行与之前UDF相同的工作,由于CLR中的字符串操作方式可以更小更快更好地处理SQL

答案 7 :(得分:1)

使用内置的sql函数可以保持简单:

set @string = 'A,B,C,D,E,F'

select * from tbl_test 
where CHARINDEX(ISNULL(tbl_test.code, 'X'), @string) > 0

如果您需要多个角色,可以使用PATINDEX。

答案 8 :(得分:0)

没什么简单的。您可以编写一个函数,该函数将接收该列表并将其拆分为可在IN()语句中查询的表。

答案 9 :(得分:0)

我知道这是一个老问题,但无论如何我想我会回复它。我从不喜欢传入逗号分隔的字符串值,所以我过去使用过XML并在xml上使用了一个连接语句,如下所示:

declare @xml as xml
set @xml = '<v id="key1" /><v id="key2" /><v id="key3" />'
select
    t.*
from
    mytable t join @xml.nodes('/*') x(n)
    on n.value('@id','varchar(50)') = t.mykey

答案 10 :(得分:0)

我认为,最简单的方法如下,

  • 选项1:

    set @string = '''A','B','C','D','E','F'''
    
    Exec ('select * from tbl_test 
    where tbl_test.code in ('+@string+')')
    
  • 选项2:

    set @string = '''A','B','C','D','E','F'''
    
    DECLARE @SQL NVARCHAR(MAX)
    
    SET @SQL='select * from tbl_test 
    where tbl_test.code in ('+@string+')'
    
    exec sp_executesql @SQL;