2013-01-10 75 views
1

可能重复分离阵列状字符串:
Help with a sql search query using a comma delimitted parameter执行存储过程与由逗号

我想要写执行一个表上的选择的存储的过程,并且需要一个输入变量类型为varchar(max)

我想发送一串由,分隔的值作为输入参数,例如:

'Jack','Jane','Joe' 

然后获取包含这些名称之一的行。

在SQL代码将

Select * from Personnel where Name in ('Jack','Joe','Jane'); 

现在我想有一个变量在我的C#应用​​程序,说strNames并填写像

string strNames = "'Jack','Joe','Jane'"; 

和这个变量发送到SP和执行它。类似于

Select * from Personnel where Name in (''Jack','Joe','Jane'') -- this is wrong 

但是如何告诉SQL Server运行此类命令?

我需要做到这一点,我知道这是可能的,请给我线索。

+0

是否可以此字符串'SELECT * FROM Table1'发送例如存储过程和SP执行它的命令?我不知何故希望sql来执行一个字符串。 –

+0

是的,这是可能的,但我永远不会那样做。 –

+0

糟糕,因为它很脆弱?或其他原因?我很好奇 –

回答

6

首先选择从表中的数据,单名不需要加引号,当你将它们传递到存储程序。

using (SqlCommand cmd = new SqlCommand("MyStoredProc", conn)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.Parameters.AddWithValue("@longFilter", "Jack,Jill,Joe"); 

    using (SqlDataReader reader = cmd.ExecuteReader()) 
    { 
     ... 
    } 
} 

然后,在存储过程中,你可以使用简单的文本功能和临时表如下分裂的逗号的字符串和一个条目添加到临时表中的字符串的每个部分:

DECLARE @temp AS TABLE (Name NVARCHAR(255)) 

IF ISNULL(@longFilter, '') <> '' 
BEGIN 
    DECLARE @s NVARCHAR(max) 
    WHILE LEN(@longFilter) > 0 
    BEGIN 
     IF CHARINDEX(',', @longFilter) > 0 
     BEGIN 
      SET @s = LTRIM(RTRIM(SUBSTRING(@longFilter, 1, CHARINDEX(',', @longFilter) - 1))) 
      SET @longFilter = SUBSTRING(@longFilter, CHARINDEX(',', @longFilter) + 1, LEN(@longFilter)) 
     END ELSE 
     BEGIN 
      SET @s = LTRIM(RTRIM(@longFilter)) 
      SET @longFilter= '' 
     END 

     -- This was missing until 20140522 
     INSERT INTO @temp (Name) VALUES (@s) 
    END 
END 

后来使用以下SELECT让所有的人它的名称是@temp或全部的列表,如果@temp不包含任何行(未经过滤的结果):

SELECT * FROM Personnel WHERE Name IN (SELECT Name FROM @temp) OR (SELECT COUNT(*) FROM @temp) = 0 
+0

中找到。这是如何工作的?它看起来并不像longFilter值被存储在临时表中。是否有一些SQL代码丢失?我错过了明显的东西吗? –

+0

其实,你是对的(有趣的是,没有人注意到它) - 实际插入临时表中的INSERT缺失。我添加了一条评论。感谢您指出了这一点! –

2

我想你需要Sql Server中的分割函数来将逗号分隔字符串分解为表。请参阅这些链接。

Split Function in Sql Server to break Comma-Separated Strings into Table

SQL User Defined Function to Parse a Delimited String

您可以使用所有的

Select * from 
Personnel where 
    Name in (select items from dbo.Split ('Jack,Joe,Jane',',')) 
+0

我知道为此目的的“最佳”功能可以在http://www.sqlservercentral.com/articles/Tally+Table/72993/ – MarkD

2

您可以简单地检查名称是否包含在字符串中。注意在年底开始的逗号,以确保您匹配的全名

string strNames = ",Jack,Joe,Jane,"; 

的在SQL成为

select * from Personnel where PATINDEX('%,' + Name + ',%', @strNames) > 0 

http://www.sqlfiddle.com/#!3/8ee5a/1

5

你可以使用Table Valued Parameters

基本上,你可以插入值的列表作为过程的参数,并把它们作为一个表,一些沿

Select * from Personnel 
    where Name in (select name from @NamesTable). 

行现在,具体

  • 要使用表值参数,参数的类型必须在sql server中预定义,使用

    create type NamesTable as table (Name varchar(50)) 
    
  • 然后,您可以使用已定义的类型作为参数的过程

    create procedure getPersonnelList 
        @NamesTable NamesTable readonly 
    as 
    begin 
        select * from personnel 
        where Name in (select Name from @NamesTable) 
    end 
    

    你可以看到,在行动中,this SQL Fiddle

  • 在你需要创建参数事情C#的一面。如果您在集合中有名称并构建字符串,则可以使用它来生成参数,如果它们是逗号分隔的字符串,则可以使用快速string.Split来处理该问题。由于我不知道你的具体情况,我假设你有一个叫做namesList<string>。你需要将其转换成一个表值参数发送到程序中,使用类似:

    DataTable tvparameter = new DataTable(); 
    tvparameter.Columns.Add("Name", typeof(string)); 
    foreach (string name in names) 
    { 
        tvparameter.Rows.Add(name); 
    } 
    

    你可以找到如何在SO Question. C#代码生成TVP的详细信息。

  • 现在你只需要将该参数发送给过程,就是这样。这是一个完整的控制台程序,它执行程序并输出结果。

    List<string> names = new List<string> { "Joe", "Jane", "Jack" }; 
    
    using (SqlConnection cnn = new SqlConnection("...")) 
    { 
        cnn.Open(); 
        using (SqlCommand cmd = new SqlCommand("getPersonnelList", cnn)) 
        { 
        cmd.CommandType = CommandType.StoredProcedure; 
    
        DataTable tvparameter = new DataTable(); 
        tvparameter.Columns.Add("Name", typeof(string)); 
        foreach (string name in names) 
        { 
         tvparameter.Rows.Add(name); 
        } 
    
        cmd.Parameters.AddWithValue("@NamesTable", tvparameter); 
    
        using (SqlDataReader dr = cmd.ExecuteReader()) 
        { 
         while (dr.Read()) 
         { 
         Console.WriteLine("{0} - {1}", dr["ID"], dr["Name"]); 
         } 
        } 
        } 
    }