简体   繁体   中英

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 . I have one Stored Procedure Delete_OrdersByCustomerIds , which deletes all the orders that are related to the CustomerIds specified.

Currently, the way I do this is to concatenate the CustomerIds into a string, ie "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:

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 . (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.

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?

Use XML for passing arrays to STPs. 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:

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

@Tom: a performance evaluation can be found here

The main lesson is, unless you are willing to use CLR code, XML is the fastest way to go:

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. In fact, XML is the fastest method that does not require any preparations in the server

If you're using SQL 2008, you can pass in a table as a parameter to a stored procedure, as explained here

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).

I use XML lists.

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))
        )
    );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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