这是场景;我有一个与 OrderIds 相关的 CustomerIds (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中这样做的唯一方法吗?
答案 0 :(得分:6)
使用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是最快的方法,不需要在服务器中做任何准备
答案 1 :(得分:5)
如果您使用的是SQL 2008,则可以将表作为参数传递给存储过程,如here所述
在早期版本的SQL中,常见的方法或者你已经拥有,或者传入一个CSV字符串以在LIKE子句中使用(我不会证明,因为我不会特别推荐这种方法)。 / p>
答案 2 :(得分: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))
)
);