Joh*_*lph 147 sql sql-server stored-procedures cursor
如何为表中的每一行调用存储过程,其中行的列是sp的输入参数而不使用Cursor?
Mar*_*ell 185
一般来说,我总是寻找基于集合的方法(有时以牺牲更改架构为代价).
但是,这个片段确实有它的位置..
-- Declare & init (2008 syntax)
DECLARE @CustomerID INT = 0
-- Iterate over all customers
WHILE (1 = 1)
BEGIN
-- Get next customerId
SELECT TOP 1 @CustomerID = CustomerID
FROM Sales.Customer
WHERE CustomerID > @CustomerId
ORDER BY CustomerID
-- Exit loop if no more customers
IF @@ROWCOUNT = 0 BREAK;
-- call your sproc
EXEC dbo.YOURSPROC @CustomerId
END
Run Code Online (Sandbox Code Playgroud)
mar*_*c_s 39
您可以执行以下操作:通过例如CustomerID(使用AdventureWorks Sales.Customer
示例表)对表进行排序,并使用WHILE循环遍历这些客户:
-- define the last customer ID handled
DECLARE @LastCustomerID INT
SET @LastCustomerID = 0
-- define the customer ID to be handled now
DECLARE @CustomerIDToHandle INT
-- select the next customer to handle
SELECT TOP 1 @CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > @LastCustomerID
ORDER BY CustomerID
-- as long as we have customers......
WHILE @CustomerIDToHandle IS NOT NULL
BEGIN
-- call your sproc
-- set the last customer handled to the one we just handled
SET @LastCustomerID = @CustomerIDToHandle
SET @CustomerIDToHandle = NULL
-- select the next customer to handle
SELECT TOP 1 @CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > @LastCustomerID
ORDER BY CustomerID
END
Run Code Online (Sandbox Code Playgroud)
这应该适用于任何表,只要您可以ORDER BY
在某些列上定义某种类型.
小智 28
DECLARE @SQL varchar(max)=''
-- MyTable has fields fld1 & fld2
Select @SQL = @SQL + 'exec myproc ' + convert(varchar(10),fld1) + ','
+ convert(varchar(10),fld2) + ';'
From MyTable
EXEC (@SQL)
Run Code Online (Sandbox Code Playgroud)
好的,所以我永远不会将这些代码投入生产,但它确实满足了您的要求.
Max*_*xxx 10
Marc的答案很好(如果我能弄明白的话,我会评论它!)
我想我会指出改变循环所以SELECT
只存在一次(在我需要的实际情况中)这样做,SELECT
非常复杂,写两次是一个有风险的维护问题).
-- define the last customer ID handled
DECLARE @LastCustomerID INT
SET @LastCustomerID = 0
-- define the customer ID to be handled now
DECLARE @CustomerIDToHandle INT
SET @CustomerIDToHandle = 1
-- as long as we have customers......
WHILE @LastCustomerID <> @CustomerIDToHandle
BEGIN
SET @LastCustomerId = @CustomerIDToHandle
-- select the next customer to handle
SELECT TOP 1 @CustomerIDToHandle = CustomerID
FROM Sales.Customer
WHERE CustomerID > @LastCustomerId
ORDER BY CustomerID
IF @CustomerIDToHandle <> @LastCustomerID
BEGIN
-- call your sproc
END
END
Run Code Online (Sandbox Code Playgroud)
如果您可以将存储过程转换为返回表的函数,则可以使用交叉应用.
例如,假设您有一个客户表,并且您想要计算其订单的总和,您将创建一个带有CustomerID并返回总和的函数.
你可以这样做:
SELECT CustomerID, CustomerSum.Total
FROM Customers
CROSS APPLY ufn_ComputeCustomerTotal(Customers.CustomerID) AS CustomerSum
Run Code Online (Sandbox Code Playgroud)
函数的位置如下:
CREATE FUNCTION ComputeCustomerTotal
(
@CustomerID INT
)
RETURNS TABLE
AS
RETURN
(
SELECT SUM(CustomerOrder.Amount) AS Total FROM CustomerOrder WHERE CustomerID = @CustomerID
)
Run Code Online (Sandbox Code Playgroud)
显然,上面的示例可以在单个查询中没有用户定义的函数的情况下完成.
缺点是函数非常有限 - 存储过程的许多特性在用户定义的函数中不可用,并且将存储过程转换为函数并不总是有效.
对于SQL Server 2005以上版本,您可以使用CROSS APPLY和表值函数执行此操作.
为了清楚起见,我指的是存储过程可以转换为表值函数的情况.
我会使用可接受的答案,但是另一种可能性是使用表变量来保存一组编号的值(在这种情况下,仅是表的ID字段),并通过具有JOIN的行号遍历那些值,以达到检索循环中所需的操作。
DECLARE @RowCnt int; SET @RowCnt = 0 -- Loop Counter
-- Use a table variable to hold numbered rows containg MyTable's ID values
DECLARE @tblLoop TABLE (RowNum int IDENTITY (1, 1) Primary key NOT NULL,
ID INT )
INSERT INTO @tblLoop (ID) SELECT ID FROM MyTable
-- Vars to use within the loop
DECLARE @Code NVarChar(10); DECLARE @Name NVarChar(100);
WHILE @RowCnt < (SELECT COUNT(RowNum) FROM @tblLoop)
BEGIN
SET @RowCnt = @RowCnt + 1
-- Do what you want here with the data stored in tblLoop for the given RowNum
SELECT @Code=Code, @Name=LongName
FROM MyTable INNER JOIN @tblLoop tL on MyTable.ID=tL.ID
WHERE tl.RowNum=@RowCnt
PRINT Convert(NVarChar(10),@RowCnt) +' '+ @Code +' '+ @Name
END
Run Code Online (Sandbox Code Playgroud)
这是已提供答案的变体,但性能应该更好,因为它不需要 ORDER BY、COUNT 或 MIN/MAX。这种方法的唯一缺点是您必须创建一个临时表来保存所有 Id(假设您的 CustomerID 列表中有间隙)。
也就是说,我同意@Mark Powell 的观点,尽管一般来说,基于集合的方法应该仍然更好。
DECLARE @tmp table (Id INT IDENTITY(1,1) PRIMARY KEY NOT NULL, CustomerID INT NOT NULL)
DECLARE @CustomerId INT
DECLARE @Id INT = 0
INSERT INTO @tmp SELECT CustomerId FROM Sales.Customer
WHILE (1=1)
BEGIN
SELECT @CustomerId = CustomerId, @Id = Id
FROM @tmp
WHERE Id = @Id + 1
IF @@rowcount = 0 BREAK;
-- call your sproc
EXEC dbo.YOURSPROC @CustomerId;
END
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
193950 次 |
最近记录: |