是否可以在不使用游标的情况下在集合上执行存储过程?

use*_*714 19 sql t-sql sql-server stored-procedures

我想在一组中的每一行上执行存储过程,而不使用类似这样的游标: 我在SQL Server 2005中使用T-SQL.我认为这可能是使用函数,但我想尽可能使用存储过程(公司标准)

SELECT EXEC dbo.Sproc @Param1 = Table1.id
FROM Table1


Jos*_*sef 18

是.如果您有一个列,您可以在表中使用以标记已处理的列,您可以使用WHILE EXISTS:

DECLARE @Id int
WHILE EXISTS(SELECT * FROM Table1 WHERE Processed='N')
BEGIN
 SELECT Top 1 @Id = id from Table1 WHERE Procesed='N'
 EXEC dbo.Sproc @Id
 UPDATE Table1 SET Processed = 'Y' WHERE Id = @Id
END
Run Code Online (Sandbox Code Playgroud)

或者,将id转储到临时表或表变量中,并在完成时删除:

DECLARE @HoldTable table (Id int PRIMARY KEY)
DECLARE @Id int
INSERT INTO @HoldTable SELECT Id FROM Table1
WHILE EXISTS(SELECT * FROM @HoldTable)
BEGIN
 SELECT @Id = id from @HoldTable
 EXEC dbo.Sproc @Id
 DELETE FROM @HoldTable where Id = @Id
END
Run Code Online (Sandbox Code Playgroud)


Joe*_*eda 14

如果您只使用SQL Server 2005或更高版本,不关心向后兼容性并且可以将代码转换为用户定义函数(而不是存储过程),那么您可以使用新的"CROSS APPLY"运算符,它确实使用与您想要的语法非常相似的语法.我在这里找到一个简短的介绍(当然,你也可以阅读BOL和MSDN)

假设您的SP返回一个名为out_int的值,您的示例可以重写为:

SELECT T.id, UDF.out_int
FROM 
    Table1 T
CROSS APPLY
    dbo.fn_My_UDF(T.id) AS UDF
Run Code Online (Sandbox Code Playgroud)

这将从Table1中检索每个"id"并使用它来调用fn_My_UDF,其结果将出现在除原始参数之外的最终结果集中.

"CROSS APPLY"的变量是"外部应用".它们是"INNER JOIN"和"LEFT JOIN"的等价物,但是可以加入表和UDF(并同时调用第二个).

如果你必须(通过尖头发老板的明确顺序)使用SPs insead,那么 - 运气不好!您将不得不使用游标,或尝试作弊:将代码更改为UDF,并创建包装SP:D.

  • @ Fernando68我在回答的最开始时指出了使用CROSS APPLY作为解决方案的3个必要条件,其中第3个是"可以将代码转换为UDF而不是SP" (12认同)

Ban*_*nkZ 2

十分之九你可以在没有光标或 while 循环的情况下做你想做的事情。但是,如果您必须使用一个循环,我发现 while 循环往往更快。

另外,如果您不想删除或更新表,您可以使用如下内容:

DECLARE @id [type]
SELECT @id = MIN([id]) FROM [table]
WHILE @id IS NOT NULL
BEGIN
    EXEC [sproc] @id
    SELECT @id = MIN([id]) FROM [table] WHERE [id] > @id
END
Run Code Online (Sandbox Code Playgroud)

  • -1 不起作用。正如理查德·科莱特所说,选择语法被破坏了。如果修复语法, while 就会陷入无限循环,正如 Tony_Henrich 所指出的那样)。我添加了一个具有工作循环的答案,但根据我的经验,速度很慢。 (2认同)