【问题标题】:Passing a List<string> to a stored procedure将 List<string> 传递给存储过程
【发布时间】:2012-04-09 14:37:15
【问题描述】:

我有一个字符串列表,我需要检查列表中的任何值是否包含在数据库表中。如果存在则返回现有值的数据集。

public DataSet CheckDocumentNumber(List<string> DocNumber)
{
   DataSet DocNum = new DataSet();
   SqlTransaction transaction = DALDBConnection.SqlConnection.BeginTransaction();

   try
   {
      string[] taleNames = new string[1];
      taleNames[0] = "DocNum";
      SqlParameter[] param = new SqlParameter[1];
      param[0] = new SqlParameter("@DocNumber", DocNumber);

      SqlHelper.FillDataset(transaction, CommandType.StoredProcedure, "spCheckDocNumber", DocNum, taleNames, param);
      transaction.Commit();
   }
   catch (Exception e)
   {
      transaction.Rollback();
   }

   return DocNum;
}

我的存储过程是

CREATE PROCEDURE spCheckDocNumber
    @DocNumber VARCHAR(MAX)
AS
BEGIN
   SELECT * FROM tblDocumentHeader WHERE DocumentNumber = @DocNumber
END

我需要知道如何将列表传递给存储过程以及如何在过程中检查列表。请帮忙

【问题讨论】:

  • 您希望 String 变量可以有多少条记录?
  • 您是否可以控制存储过程,即是否可以更改它?您需要修改存储过程以使用表值参数 (mindlesspassenger.wordpress.com/2011/05/09/…)、xml,或者使用动态 sql 将列表包含到查询中。或者您必须为列表中的每个元素调用一次存储过程,这对于大型列表来说效率很低。

标签: asp.net sql-server stored-procedures


【解决方案1】:

创建一个拆分函数,该函数根据字符拆分字符串。

GO
CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(8000))
RETURNS table
AS
RETURN (
    WITH splitter_cte AS (
      SELECT CHARINDEX(@sep, @s) as pos, 0 as lastPos
      UNION ALL
      SELECT CHARINDEX(@sep, @s, pos + 1), pos
      FROM splitter_cte
      WHERE pos > 0
    )
    SELECT SUBSTRING(@s, lastPos + 1,
                     case when pos = 0 then 80000
                     else pos - lastPos -1 end) as chunk
    FROM splitter_cte
  )
GO

SELECT *
  FROM dbo.Split(' ', 'the quick brown dog jumped over the lazy fox')
OPTION(MAXRECURSION 0);

然后使用 Split 函数以逗号分隔,然后您可以将输出用作表,然后与您要查找的表连接。

这可以使拆分逗号分隔列表变得非常容易。然后你可以传入一个字符串,其中所有 hte 值用逗号分隔。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    您可以使用如下代码: 这适用于 SQL Server 2005(及更高版本):

    create procedure IGetAListOfStrings
    @List xml -- This will recevie a List of values
      as
    begin
      -- You can load then in a temp table or use it as a subquery:
      create table #Values (ListValue nvarchar(20)); -- adjust nvarchar size
      INSERT INTO #Values
      SELECT DISTINCT params.p.value('.','varchar(20)') -- adjust nvarchar size
      FROM @List.nodes('/params/p') as params(p);
      ...
    end
    

    您必须使用如下参数调用此过程:

    exec IGetAListOfValues
    @List = '<params> <p>string1</p> <p>string2</p> </params>' -- xml parameter
    

    nodes 函数使用 xPath 表达式。在本例中,它是 /params/p,因此 XML 使用 &lt;params&gt; 作为根,&lt;p&gt; 作为元素。

    有关详细信息,请参阅此答案: Passing List of values to stored procedure

    【讨论】:

      【解决方案3】:

      也许您可以在 sql 中改用 In operatorhttp://vyaskn.tripod.com/passing_arrays_to_stored_procedures.htm 上也有一些关于如何使用它的教程。

      【讨论】:

      • 如何对数据库中逗号分隔的字符串值进行IN谓词操作?
      • 您需要使用动态 sql 来完成此操作,但这绝对是可能的。
      • @Mellamokb OP 需要先将集合传递到数据库。
      • 以这种方式使用动态 SQL 通常是不安全的(SQL 注入)。
      【解决方案4】:

      您必须自己编写代码,使用 xml sql 数据类型是一个不错的选择。

      有关代码示例,请参阅:Passing an array of parameters to a stored procedure

      【讨论】:

        【解决方案5】:

        将 XML 发送到 SQL

                    List<string> lst = new List<string> {
                                                                "1",
                                                                "2",
                                                                "3"
                                                        };
        
                    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); 
                    namespaces.Add(string.Empty, string.Empty);
                    StringBuilder sb = new StringBuilder();
                    using (var sw = new StringWriter(sb)) //serialize
                    {
                        var serializer = new XmlSerializer(typeof (List<string>));
                        serializer.Serialize(sw, lst, namespaces);
                    }
        

        现在,将 SB 作为参数发送到 sql。

        仅此而已。

        不要使用 CSV。

        【讨论】:

        • 我不应该使用SQlBulkCopy吗?因此,发送数据库表中的所有记录并将其加入您的存储过程。最初在参数列表中向存储过程发送一个唯一的 GUID,并在表中发送这个相同的 GUID 以跟踪相关记录。在存储过程中完成作业后,只需在 elaving 之前从表中删除关联的记录。你说什么?
        • 我没有看到 Bulk Copy 之间有任何关系。批量复制只是不要将插入内容保存在 LOG 文件中。不要使用 CSV 值(就像其他人建议的那样)。使用通用格式:XML。
        猜你喜欢
        • 2010-09-17
        • 2016-06-09
        • 2011-10-23
        • 2013-11-26
        • 2015-11-20
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多