循环遍历记录以执行存储过程并存储结果
Looping through records to execute a stored procedure and store the result
我有一个存储过程 sp_OrderPrice_Calc
,它接受一个 OrderNumber
和 returns 一个标量值 Order Price
。我正在尝试循环上面的存储过程以获取订单号列表 而无需 使用游标。
我有以下逻辑,但输出不符合预期。我真的很感激任何 suggestions/changes.
---------------------------------------------------------------------------------
DECLARE @orderInfo AS TABLE
(
ID INT IDENTITY(1,1),
CompanyName VARCHAR(40),
OrderNumber VARCHAR(40),
DeliveryType VARCHAR(40),
OrderPrice DECIMAL(6,1)
)
INSERT INTO @orderInfo (CompanyName, OrderNumber, DeliveryType)
SELECT CompanyName, OrderNumber, DeliveryType
FROM OrderData
DECLARE @ID INT = 1, @OrderNumber VARCHAR(40), @OrderPrice DECIMAL(6,1)
WHILE @ID IS NOT NULL
BEGIN
SELECT @OrderNumber = OrderNumber
FROM @orderInfo
WHERE ID = @ID
INSERT INTO @orderInfo (OrderPrice)
EXEC sp_OrderPrice_Calc @Order_Number = @OrderNumber, @Order_Price = @OrderPrice
SELECT @ID = MIN(ID)
FROM @OrderInfo
WHERE ID > @ID;
END
SELECT * FROM @OrderInfo
---------------------------------------------------------------------------------
注意: 我已经创建了存储过程,它应该将 @Order_Number
作为输入,将 @order_Price
作为输出,我在上面的逻辑中使用了它
例如
CREATE PROCEDURE [dbo].[spCDS_TP_TW_limit]
@Order_Number VARCHAR(50) = '',
@order_Price decimal(6,1) OUTPUT
AS
以上逻辑为输出中的每个 Order_Number 记录返回“Null”
CompanyName OrderNumber DeliveryType OrderPrice
--------------------------------------------------
ABBCCC 123456 Standard NULL
DDDDEE 147852 Standard NULL
EEEFFF 159635 Priority NULL
FFFFGG 163589 Ground NULL
你这里有几个误区。
首先,您需要了解,当您使用 insert into table (columns...) exec procedure
形式时,插入的内容是存储过程的 结果集 。换句话说,过程中 select 语句的任何结果。如果您的存储过程没有结果集,则没有可插入的内容。请注意,output 参数与结果集 not 相同。观察如果 运行 以下批次会发生什么:
create table t(result varchar(30))
go
create procedure p (@result varchar(30) = null output) as
begin
set @result = 'this is the output parameter';
select 'this is the result set';
end
go
declare @param varchar(30);
insert t (result) exec p @param output;
select * from t;
select @param;
在此脚本执行结束时,table t
将有一行值为““这是结果集”。 @param
变量的值将是“这是输出参数”。
好的,现在让我们看看您的程序中发生了什么。
您使用 insert ... exec
模式,因此存储过程的结果集将 插入 作为新行到您的 @orderInfo
table.
但是从您所写的内容来看,您似乎打算将价格作为 output
参数值提供,供您的 @orderPrice
变量使用。它实际上不会这样做,因为您还没有将它用作输出参数。您遗漏了 output
关键字。
我希望您的存储过程根本没有结果集。这意味着没有任何内容被插入 table.
即使存储过程做了return一个结果集,你也在做一个insert
。 insert
将创建新行,它不会更新现有行的 OrderPrice
列的值。
您可能打算做的是:
While @ID IS NOT NULL
BEGIN
Select @OrderNumber = OrderNumber;
From @orderInfo Where ID = @ID;
Exec sp_OrderPrice_Calc
@Order_Number = @OrderNumber,
@Order_Price = @OrderPrice output; -- output keyword is required both here and in the procedure definition
update @orderInfo set OrderPrice = @orderPrice where ID = @ID; -- update, not insert.
Select @ID = MIN(ID) From @OrderInfo where ID > @ID;
END
这里可能有更好的解决方案。如果您的存储过程可以重写为 user defined function,则根本不需要循环:
select CompanyName, OrderNumber, DeliveryType, OrderPrice = myOrderPriceFunction(...)
From OrderData;
我有一个存储过程 sp_OrderPrice_Calc
,它接受一个 OrderNumber
和 returns 一个标量值 Order Price
。我正在尝试循环上面的存储过程以获取订单号列表 而无需 使用游标。
我有以下逻辑,但输出不符合预期。我真的很感激任何 suggestions/changes.
---------------------------------------------------------------------------------
DECLARE @orderInfo AS TABLE
(
ID INT IDENTITY(1,1),
CompanyName VARCHAR(40),
OrderNumber VARCHAR(40),
DeliveryType VARCHAR(40),
OrderPrice DECIMAL(6,1)
)
INSERT INTO @orderInfo (CompanyName, OrderNumber, DeliveryType)
SELECT CompanyName, OrderNumber, DeliveryType
FROM OrderData
DECLARE @ID INT = 1, @OrderNumber VARCHAR(40), @OrderPrice DECIMAL(6,1)
WHILE @ID IS NOT NULL
BEGIN
SELECT @OrderNumber = OrderNumber
FROM @orderInfo
WHERE ID = @ID
INSERT INTO @orderInfo (OrderPrice)
EXEC sp_OrderPrice_Calc @Order_Number = @OrderNumber, @Order_Price = @OrderPrice
SELECT @ID = MIN(ID)
FROM @OrderInfo
WHERE ID > @ID;
END
SELECT * FROM @OrderInfo
---------------------------------------------------------------------------------
注意: 我已经创建了存储过程,它应该将 @Order_Number
作为输入,将 @order_Price
作为输出,我在上面的逻辑中使用了它
例如
CREATE PROCEDURE [dbo].[spCDS_TP_TW_limit]
@Order_Number VARCHAR(50) = '',
@order_Price decimal(6,1) OUTPUT
AS
以上逻辑为输出中的每个 Order_Number 记录返回“Null”
CompanyName OrderNumber DeliveryType OrderPrice
--------------------------------------------------
ABBCCC 123456 Standard NULL
DDDDEE 147852 Standard NULL
EEEFFF 159635 Priority NULL
FFFFGG 163589 Ground NULL
你这里有几个误区。
首先,您需要了解,当您使用 insert into table (columns...) exec procedure
形式时,插入的内容是存储过程的 结果集 。换句话说,过程中 select 语句的任何结果。如果您的存储过程没有结果集,则没有可插入的内容。请注意,output 参数与结果集 not 相同。观察如果 运行 以下批次会发生什么:
create table t(result varchar(30))
go
create procedure p (@result varchar(30) = null output) as
begin
set @result = 'this is the output parameter';
select 'this is the result set';
end
go
declare @param varchar(30);
insert t (result) exec p @param output;
select * from t;
select @param;
在此脚本执行结束时,table t
将有一行值为““这是结果集”。 @param
变量的值将是“这是输出参数”。
好的,现在让我们看看您的程序中发生了什么。
您使用 insert ... exec
模式,因此存储过程的结果集将 插入 作为新行到您的 @orderInfo
table.
但是从您所写的内容来看,您似乎打算将价格作为 output
参数值提供,供您的 @orderPrice
变量使用。它实际上不会这样做,因为您还没有将它用作输出参数。您遗漏了 output
关键字。
我希望您的存储过程根本没有结果集。这意味着没有任何内容被插入 table.
即使存储过程做了return一个结果集,你也在做一个insert
。 insert
将创建新行,它不会更新现有行的 OrderPrice
列的值。
您可能打算做的是:
While @ID IS NOT NULL
BEGIN
Select @OrderNumber = OrderNumber;
From @orderInfo Where ID = @ID;
Exec sp_OrderPrice_Calc
@Order_Number = @OrderNumber,
@Order_Price = @OrderPrice output; -- output keyword is required both here and in the procedure definition
update @orderInfo set OrderPrice = @orderPrice where ID = @ID; -- update, not insert.
Select @ID = MIN(ID) From @OrderInfo where ID > @ID;
END
这里可能有更好的解决方案。如果您的存储过程可以重写为 user defined function,则根本不需要循环:
select CompanyName, OrderNumber, DeliveryType, OrderPrice = myOrderPriceFunction(...)
From OrderData;