简体   繁体   English

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

[英]Comma Delimited SQL string Need to separated

I have this string that i am getting from .net application A,B,C,D,E,F, 我有这个字符串,我从.net应用程序A,B,C,D,E,F,

I wanted to write a sql select statement like 我想编写一个像sql select语句一样的

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

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

This wont work in t-SQL because it is using the @string as one string it is not separating the values. 这在t-SQL中不起作用,因为它使用@string作为一个字符串,而不是将值分开。 Is there any ways i can do this? 有什么方法可以做到这一点吗?

3 options 3个选项

  1. Use a regular expression to replace the "," with "','" so that it becomes a proper ('A','B'...) list 使用正则表达式将“,”替换为“','”,以便它成为正确的('A','B'...)列表
  2. Convert the list to XML and then parse the XML in your SELECT 将列表转换为XML,然后在SELECT中解析XML
  3. Write a SPLIT function to convert comma delimited lists to tables 编写SPLIT函数以将逗号分隔的列表转换为表

Very frequently asked question! 很常见的问题! What you want is a table-valued function. 你想要的是一个表值函数。

But don't reinvent the wheel by writing your own, I found dozens just by Googling sql split . 但是不要通过编写自己来重新发明轮子,我通过Googling sql split找到了几十个。 Here's one from Microsoft: 这是来自微软的一个:

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

I used to use dynamic SQL for this, but that meant I had to dig up the code and copy it into each new app. 我曾经使用动态SQL,但这意味着我必须挖掘代码并将其复制到每个新应用程序中。 Now I don't even have to think about it. 现在我甚至不用考虑它。

A dynamic IN clause means either: 动态IN子句意味着:

  1. Converting the comma separated list into a temporary table to join onto 将逗号分隔列表转换为要加入的临时表
  2. Using dynamic SQL (EXEC or EXEC sp_executesql) 使用动态SQL(EXEC或EXEC sp_executesql)

Dynamic SQL example 动态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

Mind that sp_executesql is 2005+, and preferred because it will cache the query plan. 请注意, sp_executesql是2005+,并且首选,因为它将缓存查询计划。 Read The Curse and Blessings of Dynamic SQL for more detail, but be aware of SQL injection attacks . 阅读动态SQL的诅咒和祝福更多细节,但要注意SQL注入攻击

Create a User Defined Function that takes the string as input and returns a table: 创建一个用户定义的函数,它将字符串作为输入并返回一个表:

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

Then adjust your Select statement: 然后调整Select语句:

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

It think the easiest way to do it, will be, dynamic SQL generation: 它认为最简单的方法就是动态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

Here is a function that returns a delimited String as a set of rows 这是一个函数,它将分隔的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

You have several options: 你有几个选择:

  • If you are OK with it, just compose the SQL statement dynamically before making call to SQL. 如果你没问题,只需在调用SQL之前动态编写SQL语句 There is a limitation on the number of values in the IN statement IN语句中的值数量有限制
  • Use Table-valued UDF that splits the string and returns the table. 使用表值UDF分割字符串并返回表。 Then your query would either use IN or better just JOIN statement (among other implementations I favor SQL User Defined Function to Parse a Delimited String ). 然后你的查询将使用IN或更好的只是JOIN语句(在其他实现中,我支持SQL用户定义函数来解析分隔字符串 )。

The you code would be: 你的代码是:

select     tbl_test.*
from       tbl_test 
inner join fn_ParseText2Table(@string) x
       on  tbl_test.code = x.txt_value 
  • Since you use SQL Server 2005, you can write CLR Table-valued UDF that would do the same job as previous UDF does, which would be much smaller and faster since string operations in CLR are way better handled that in SQL . 由于您使用的是SQL Server 2005,因此您可以编写CLR表值UDF ,它将执行与之前UDF相同的工作,这将更小更快,因为CLR中的字符串操作在SQL处理方式更好。

You could keep it really simple with built-in sql functions: 你可以使用内置的sql函数保持它非常简单:

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

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

PATINDEX can be used in case you need more than one character. 如果您需要多个字符,可以使用PATINDEX。

I know this is an old question, but I thought I would post an answer to it anyway. 我知道这是一个老问题,但我想我还是会发一个答案。 I never liked passing in comma delimited string values, so I have used XML in the past and used a join statement on the xml like so: 我从不喜欢传入逗号分隔的字符串值,所以我过去使用过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

Nothing simple. 没什么简单的。 You can write a function that will take in that list and split it apart into a table you can query against in the IN() statement. 您可以编写一个函数,该函数将接收该列表并将其拆分为可在IN()语句中查询的表。

I think, the easiest way is as below, 我想,最简单的方法如下,

  • Option1: 选项1:

     set @string = '''A','B','C','D','E','F''' Exec ('select * from tbl_test where tbl_test.code in ('+@string+')') 
  • Option2: 选项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; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM