【问题标题】:SQL - Is there a better way of passing a list of keys, for use in a where clause, into a Stored Procedure?SQL - 是否有更好的方法将用于 where 子句的键列表传递到存储过程?
【发布时间】:2009-11-16 14:46:12
【问题描述】:

这是场景;我有一个具有相关 OrderIdsCustomerIds (1, 2, 3) 列表。我有一个存储过程Delete_OrdersByCustomerIds,它会删除与指定的CustomerIds 相关的所有订单。

目前,我这样做的方法是将 CustomerIds 连接成一个字符串,即“1,2,3”。然后我将此字符串传递给我的存储过程,并使用以下函数创建一个我可以加入的 Int 表:

CREATE FUNCTION [dbo].[iter$simple_intlist_to_tbl] (@list nvarchar(MAX))
   RETURNS @tbl TABLE (number int NOT NULL) AS
BEGIN
   DECLARE @pos        int,
           @nextpos    int,
           @valuelen   int

   SELECT @pos = 0, @nextpos = 1

   WHILE @nextpos > 0
   BEGIN
      SELECT @nextpos = charindex(',', @list, @pos + 1)
      SELECT @valuelen = CASE WHEN @nextpos > 0
                              THEN @nextpos
                              ELSE len(@list) + 1
                         END - @pos - 1
      INSERT @tbl (number)
         VALUES (convert(int, substring(@list, @pos + 1, @valuelen)))
      SELECT @pos = @nextpos
   END
  RETURN
END

然后我只做一个DELETE FROM Orders WHERE CustomerId IN iter$simple_intlist_to_tbl(@CustomerIds).number。 (语法可能不在这里,我在大声思考。)

我不禁觉得这不好。有没有更好的方法来实现同样的目标?我不想自己构建 SQL 语句,我目前正在使用标准的 .Net ADO 包装器。

查看其他问题,即这个one,看来我的方法是可以接受的,那么这是SQL 2005中唯一的方法吗?

【问题讨论】:

    标签: c# sql sql-server-2005 stored-procedures ado.net


    【解决方案1】:

    使用 XML 将数组传递给 STP。示例:

    CREATE PROC myProc
    (
        @list AS XML
    )
    AS
    (
        SELECT items.item.value('.', 'VARCHAR(MAX)') AS Item
        FROM @list.nodes('list/item') items(item)
    )
    

    调用 STP:

     myProc '<list><item>a</item><item>b</item></list>'
    

    @Tom:性能评测可以找here

    主要的教训是,除非你愿意使用 CLR 代码,否则 XML 是最快的方法:

    在我的测试中,XML 的执行时间比 CLR 高 40-60%,但它的速度是迭代方法的两倍。其实XML是最快的方法,不需要服务器做任何准备

    【讨论】:

    • 您是否对这种方法进行过性能比较或看到过?这是一种有趣的方法。
    【解决方案2】:

    如果您使用的是 SQL 2008,则可以将表作为参数传递给存储过程,如 here 所述

    在早期版本的 SQL 中,常用方法是您已有的方法,或者传入要在 LIKE 子句中使用的 CSV 字符串(我不会演示,因为我不会特别推荐这种方法)。

    【讨论】:

    • 这不会导致类型转换异常吗?
    • 而且,我使用的是 SQL 2005,而不是 2008 - 请参阅我的问题的最后一段。我也会重新标记。
    • 同意在 SQL 2005 及更早版本中使用函数。也同意 XQuery 解决方案。表参数似乎很难配置和使用……是吗?
    • 抱歉,第一次没有发现 SQL 2005 位。就个人而言,我倾向于使用“函数拆分为表变量方法”,就像您已经在做的那样。我提到的 LIKE 方法不会导致良好的索引使用。 XML 方法是一种替代方法,但我个人不使用它。我不知道 XML 方法和您当前方法之间的性能差异是什么,您需要同时尝试并比较。
    【解决方案3】:

    我使用 XML 列表。

    我使用这种存储过程:

    CREATE PROCEDURE [dbo].[GetUsersInList]
        @UserList nvarchar(MAX)
    AS
    BEGIN
        DECLARE @DocHandle int
        DECLARE @UsersListTable table (
            [UserID] bigint
        )
    
        EXEC sp_xml_preparedocument @DocHandle OUTPUT, @UserList
    
        INSERT INTO
            @UsersListTable ([UserID])
        SELECT
            doc.Value [UserID]
        FROM
            OPENXML(@DocHandle, '/List/Item', 1) WITH ([Value] int) doc
    
        EXEC sp_xml_removedocument @DocHandle
    
        SELECT
            *,
            IsNull(cast(TechID as varchar) + ' - ' + DisplayName, DisplayName) [FriendlyName]
        FROM
            dbo.[Users]
        WHERE
            [ID] IN (SELECT [UserID] FROM @UsersListTable)
    END
    

    创建这种列表:

    var list =
        new XElement("List",
            users.Select(user =>
                new XElement("Item", new XAttribute("Value", user.Id))
            )
        );
    

    【讨论】:

    • 我不会在 SQL Server 2005+ 中使用 sp_xml_preparedocument。我会使用节点()等
    • 天哪,仅仅连接几个数字并调用一个函数是不是很困难,不是吗?为努力+1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多