C#SQL Server - 将列表传递给存储过程

Bre*_*ett 105 c# sql stored-procedures

我从我的C#代码调用SQL Server存储过程:

using (SqlConnection conn = new SqlConnection(connstring))
{
   conn.Open();
   using (SqlCommand cmd = new SqlCommand("InsertQuerySPROC", conn))
   {
      cmd.CommandType = CommandType.StoredProcedure;

      var STableParameter = cmd.Parameters.AddWithValue("@QueryTable", QueryTable);
      var NDistanceParameter = cmd.Parameters.AddWithValue("@NDistanceThreshold", NDistanceThreshold);
      var RDistanceParameter = cmd.Parameters.AddWithValue(@"RDistanceThreshold", RDistanceThreshold);

      STableParameter .SqlDbType = SqlDbType.Structured;
      NDistanceParameter.SqlDbType = SqlDbType.Int;
      RDistanceParameter.SqlDbType = SqlDbType.Int;

      // Execute the query
      SqlDataReader QueryReader = cmd.ExecuteReader();
Run Code Online (Sandbox Code Playgroud)

我的存储过程是相当标准的但是加入了QueryTable(因此需要使用存储过程).

现在:我想List<string>在参数集中添加一个字符串列表.例如,我的存储过程查询如下所示:

SELECT feature 
FROM table1 t1 
INNER JOIN @QueryTable t2 ON t1.fid = t2.fid 
WHERE title IN <LIST_OF_STRINGS_GOES_HERE>
Run Code Online (Sandbox Code Playgroud)

但是,字符串列表是动态的,几百长.

有没有办法将字符串列表传递List<string>给存储过程??? 或者有更好的方法吗?

非常感谢,布雷特

Red*_*dth 168

如果您使用的是SQL Server 2008,则会有一个名为"用户定义的表类型"的新功能.以下是如何使用它的示例:

创建用户定义的表类型:

CREATE TYPE [dbo].[StringList] AS TABLE(
    [Item] [NVARCHAR](MAX) NULL
);
Run Code Online (Sandbox Code Playgroud)

接下来,您需要在存储过程中正确使用它:

CREATE PROCEDURE [dbo].[sp_UseStringList]
    @list StringList READONLY
AS
BEGIN
    -- Just return the items we passed in
    SELECT l.Item FROM @list l;
END
Run Code Online (Sandbox Code Playgroud)

最后这里有一些sql在c#中使用它:

using (var con = new SqlConnection(connstring))
{
    con.Open();

    using (SqlCommand cmd = new SqlCommand("exec sp_UseStringList @list", con))
    {
        using (var table = new DataTable()) {
          table.Columns.Add("Item", typeof(string));

          for (int i = 0; i < 10; i++)
            table.Rows.Add("Item " + i.ToString());

          var pList = new SqlParameter("@list", SqlDbType.Structured);
          pList.TypeName = "dbo.StringList";
          pList.Value = table;

          cmd.Parameters.Add(pList);

          using (var dr = cmd.ExecuteReader())
          {
            while (dr.Read())
                Console.WriteLine(dr["Item"].ToString());
          }
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

从SSMS执行此操作

DECLARE @list AS StringList

INSERT INTO @list VALUES ('Apple')
INSERT INTO @list VALUES ('Banana')
INSERT INTO @list VALUES ('Orange')

-- Alternatively, you can populate @list with an INSERT-SELECT
INSERT INTO @list
   SELECT Name FROM Fruits

EXEC sp_UseStringList @list
Run Code Online (Sandbox Code Playgroud)

  • 是否必须定义数据表来设置参数的值?还有其他任何轻便的方 (10认同)
  • **如果您使用LINQ2SQL,请小心使用此解决方案,因为它不支持用户定义的表类型作为参数!!!**使用逗号分隔列表和解析器函数可以在Jon Raynor的答案中找到解决方法,但是这样也有缺点.... (7认同)
  • @Fazi在这种情况下,不要使用Linq2SQL.最好在T-SQL中进行字符串连接和解析 (3认同)
  • 我们尝试了但是我们发现Enitiy框架不支持它的缺点 (2认同)
  • 是的,那么您实际上如何从SSMS执行此操作? (2认同)

Tej*_*ejs 20

这种情况下的典型模式是在逗号分隔列表中传递元素,然后在SQL中将其拆分为可以使用的表.大多数人通常会创建一个指定的函数,如下所示:

 INSERT INTO <SomeTempTable>
 SELECT item FROM dbo.SplitCommaString(@myParameter)
Run Code Online (Sandbox Code Playgroud)

然后您可以在其他查​​询中使用它.

  • 让我为完整性提供dbo.SplitCommaString实现的链接:http://goo.gl/P9ROs (15认同)
  • 当你的某个数据字段中有逗号时会发生什么? (3认同)
  • 用管道来划定它. (3认同)
  • 然后使用不在数据字段中的内容.如有必要,清理您的数据,但我从未见过的管道数据不多.如果他们绝对需要找到一些其他的角色,如¤或§. (2认同)

Jon*_*nor 7

不,数组/列表不能直接传递给SQL Server.

可以使用以下选项:

  1. 传递以逗号分隔的列表,然后在SQL中使用函数拆分列表.逗号分隔列表很可能作为Nvarchar()传递
  2. 传递xml并在SQL Server中有一个函数解析列表中每​​个值的XML
  3. 使用新定义的用户定义表类型(SQL 2008)
  4. 动态构建SQL并将原始列表作为"1,2,3,4"传递并构建SQL语句.这很容易发生SQL注入攻击,但它会起作用.

  • 这是对可能选项的一个很好的总结。在我看来,第三个选项是最好的选择,并且不要将第四个选项用于此目的。 (2认同)