简体   繁体   English

SQL - 是否有更好的方法将用于where子句的密钥列表传递到存储过程?

[英]SQL - Is there a better way of passing a list of keys, for use in a where clause, into a Stored Procedure?

Here's the scenario; 这是场景; I have a list of CustomerIds (1, 2, 3) that have relating OrderIds . 我有一个与OrderIds相关的CustomerIds (1,2,3) 列表 I have one Stored Procedure Delete_OrdersByCustomerIds , which deletes all the orders that are related to the CustomerIds specified. 我有一个存储过程Delete_OrdersByCustomerIds ,它删除与指定的CustomerIds相关的所有订单。

Currently, the way I do this is to concatenate the CustomerIds into a string, ie "1,2,3". 目前,我这样做的方法是将CustomerIds连接成一个字符串,即“1,2,3”。 I then pass this string through to my stored procedure and use the following function to create a Table of Int's that I can join on: 然后我将此字符串传递给我的存储过程并使用以下函数创建一个我可以加入的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

I then just do a DELETE FROM Orders WHERE CustomerId IN iter$simple_intlist_to_tbl(@CustomerIds).number . 然后,我只是执行DELETE FROM Orders WHERE CustomerId IN iter$simple_intlist_to_tbl(@CustomerIds).number (The syntax might not be right here, I'm thinking out loud.) (语法可能不在这里,我在大声思考。)

I can't help feeling this is bad . 我不禁觉得这很糟糕 Is there a better way of achieving the same thing? 是否有更好的方法来实现同样的目标? I don't want to build up the SQL statement myself, I'm currently using the standard .Net ADO wrappers. 我不想自己构建SQL语句,我目前正在使用标准的.Net ADO包装器。

Looking at other questions, ie this one , it seems my method is acceptable, so is this the only way to do it in SQL 2005? 综观其他问题,即这一个 ,看来我的方法是可以接受的,所以这是做在SQL 2005的唯一途径?

Use XML for passing arrays to STPs. 使用XML将数组传递给STP。 Example: 例:

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

calling the STP: 打电话给STP:

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

@Tom: a performance evaluation can be found here @Tom:可以在这里找到性能评估

The main lesson is, unless you are willing to use CLR code, XML is the fastest way to go: 主要的教训是,除非您愿意使用CLR代码,否则XML是最快的方法:

In my tests, the execution times for XML are 40-60 % higher than for the CLR, but it is twice as fast as the iterative method. 在我的测试中,XML的执行时间比CLR高40-60%,但它的速度是迭代方法的两倍。 In fact, XML is the fastest method that does not require any preparations in the server 事实上,XML是最快的方法,不需要在服务器中做任何准备

If you're using SQL 2008, you can pass in a table as a parameter to a stored procedure, as explained here 如果您使用SQL 2008,您可以通过在表中作为参数传递给存储过程,如解释在这里

In earlier versions of SQL, the common approaches are either as you already have, or passing in a CSV string to be used within a LIKE clause (I won't demonstrate as I wouldn't particularly recommend the approach). 在早期版本的SQL中,常见的方法是您已经拥有的,或者传递一个CSV字符串以在LIKE子句中使用(我不会证明,因为我不会特别推荐这种方法)。

I use XML lists. 我使用XML列表。

I use this sort of stored procedure: 我使用这种存储过程:

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

To create this sort of list: 要创建此类列表:

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

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

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