每次调用存储过程时,使用带有游标的存储过程只更新一行
Update only one row using a stored procedure with a cursor, each time the stored procedure is called
我对使用游标还很陌生。
每次存储过程为 运行 时,我都试图只更改一行(不是全部)更改运费值。任何帮助将不胜感激。
[代码]
SELECT * FROM NorthWind.dbo.Orders ORDER BY ShipVia, Freight --Checking...
IF (OBJECT_ID('spUpateOrder')IS NOT NULL) DROP PROCEDURE spUpateOrder;
GO
CREATE PROCEDURE spUpateOrder
@CustomerID nchar(5)
,@EmployeeID [int]
,@OrderDate datetime = NULL
,@RequiredDate datetime = NULL
,@ShippedDate datetime = NULL
,@ShipVia int = 1 -- may have a primary shipper
,@Freight money
,@ShipName nvarchar(40) = NULL
,@ShipAddress nvarchar(60) = NULL
,@ShipCity nvarchar(15) = NULL
,@ShipRegion nvarchar(15) = NULL
,@ShipPostalCode nvarchar(10) = NULL
,@ShipCountry nvarchar(15) = NULL
AS
DECLARE UpdateOneRowCur CURSOR LOCAL FOR
SELECT Freight FROM [NorthWind].[dbo].[Orders] -- WHERE Freight = NULL
WHERE CustomerID = 'alfki' AND Freight < 30.00 AND Freight IS NOT NULL
SET @Freight = @Freight + .1
OPEN UpdateOneRowCur
FETCH NEXT FROM UpdateOneRowCur INTO @Freight
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC spUpateOrder
@CustomerID
,@EmployeeID
,@OrderDate
,@RequiredDate
,@ShippedDate
,@ShipVia --= 1, -- may have a primary shipper
,@Freight
,@ShipName
,@ShipAddress
,@ShipCity
,@ShipRegion
,@ShipPostalCode
,@ShipCountry
FETCH NEXT FROM UpdateOneRowCur INTO @Freight
RETURN @@Identity
DECLARE @Ret int
EXECUTE @Ret = @Freight;
--EXECUTE @Ret = spUpateOrder --'alfki', 7, '1/1/2013', null, null, 1
, null;
IF @ret = 0
PRINT 'error!';
ELSE
PRINT 'OrderId entered: ' + CAST(@ret as varchar);
CLOSE UpdateOneRowCur
DEALLOCATE UpdateOneRowCur
END;
GO
Declare @Ret int
EXEC @Ret = spUpateOrder 'alfki', 7, '1/1/2013', null, null, 1, 25.99;
GO
[/代码]
这段代码确实一次更改了所有行,但我只希望它更改它找到的第一行,然后在下次我 运行 存储过程时更改它找到的第二行。不确定该怎么做?注意:为了测试它,我创建了一些具有相同运费值 25.99 的新行。
答案:
这是我每次执行存储过程时只更改一行的方法:(这确实有效!)
[code]
--============== UPdate only one row ===============--
CREATE PROCEDURE uspUpdateOrder
@Freight money --Testing.
AS
/*
Created by: Chris Singleton
02/26/2017
Updates each row that has 25.99 where the customer's name is 'alfki'.
*/
BEGIN
--DECLARE @Freight
UPDATE top (1) Northwind.dbo.Orders
SET Freight = @Freight + .1
WHERE CustomerID = 'alfki' AND Freight = 25.99
END;
--============ Call the Stored Procedure =============--
GO
-- the call:
Declare @Ret int
EXEC @Ret = uspUpdateOrder 25.99;
If @ret = 0
print 'error!';
else
print 'OrderId entered: ' + cast(@ret as varchar);
DROP PROCEDURE uspUpdateOrder
GO
SELECT * FROM [Northwind].[dbo].[Orders] WHERE CustomerID = 'alfki'
--====================================--
[/code]
您的代码中存在多个问题:
- 您正在将“@Freight”作为参数传递。在您的示例中,您为此变量分配了一个值 25.99
- 然后将变量的值增加 0.1 (SET @Freight = @Freight + .1)。因此,在您的示例中,变量的值将为 26.09
- 然后你 运行 查询并用你的查询结果覆盖 @Freight 的值 (FETCH NEXT FROM UpdateOneRowCur INTO @Freight)。此时,步骤1和2完全多余,因为你正在覆盖之前的内容。
- 您正在使用一个循环,并且在您的循环中,您不断从查询的结果集中读取一行并覆盖@Freigh 的值并调用更新过程。
如果你只需要更新第一行,那么你可以这样写:
SELECT top 1 @Freight = Freight FROM [NorthWind].[dbo].[Orders] -- WHERE Freight = NULL
WHERE CustomerID = 'alfki' AND Freight < 30.00 AND Freight IS NOT NULL
SET @Freight = @Freight + .1 -- I'm not sure if you realy want to do this or not
我在您的查询中所做的更改是我只返回一行 (select top 1
),同时分配 @Freight
的值
您真的不需要任何游标或循环。
Sparrow 在某种程度上是正确的,我不需要光标来进行编码,所以我给了 Sparrow 分数,但是为了使用过滤器专注于一行,您可以这样做。
[Code]
--============== UPdate only one row ===============--
CREATE PROCEDURE uspUpdateOrder
@Freight money --Testing.
AS
/*
Created by: Chris Singleton
02/26/2017
Updates each row that has 25.99 where the customer's name is 'alfki'.
*/
BEGIN
--DECLARE @Freight
UPDATE top (1) Northwind.dbo.Orders
SET Freight = @Freight + .1
WHERE CustomerID = 'alfki' AND Freight = 25.99
END;
--============ Call the Stored Procedure =============--
GO
-- the call:
Declare @Ret int
EXEC @Ret = uspUpdateOrder 25.99;
If @ret = 0
print 'error!';
else
print 'OrderId entered: ' + cast(@ret as varchar);
DROP PROCEDURE uspUpdateOrder
GO
SELECT * FROM [Northwind].[dbo].[Orders] WHERE CustomerID = 'alfki'
--====================================--
[/Code]
注意:您可以结合使用更新子句 TOP (1) 和 where 子句作为过滤器来关注该行。这个作品不错!
我对使用游标还很陌生。 每次存储过程为 运行 时,我都试图只更改一行(不是全部)更改运费值。任何帮助将不胜感激。
[代码]
SELECT * FROM NorthWind.dbo.Orders ORDER BY ShipVia, Freight --Checking...
IF (OBJECT_ID('spUpateOrder')IS NOT NULL) DROP PROCEDURE spUpateOrder;
GO
CREATE PROCEDURE spUpateOrder
@CustomerID nchar(5)
,@EmployeeID [int]
,@OrderDate datetime = NULL
,@RequiredDate datetime = NULL
,@ShippedDate datetime = NULL
,@ShipVia int = 1 -- may have a primary shipper
,@Freight money
,@ShipName nvarchar(40) = NULL
,@ShipAddress nvarchar(60) = NULL
,@ShipCity nvarchar(15) = NULL
,@ShipRegion nvarchar(15) = NULL
,@ShipPostalCode nvarchar(10) = NULL
,@ShipCountry nvarchar(15) = NULL
AS
DECLARE UpdateOneRowCur CURSOR LOCAL FOR
SELECT Freight FROM [NorthWind].[dbo].[Orders] -- WHERE Freight = NULL
WHERE CustomerID = 'alfki' AND Freight < 30.00 AND Freight IS NOT NULL
SET @Freight = @Freight + .1
OPEN UpdateOneRowCur
FETCH NEXT FROM UpdateOneRowCur INTO @Freight
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC spUpateOrder
@CustomerID
,@EmployeeID
,@OrderDate
,@RequiredDate
,@ShippedDate
,@ShipVia --= 1, -- may have a primary shipper
,@Freight
,@ShipName
,@ShipAddress
,@ShipCity
,@ShipRegion
,@ShipPostalCode
,@ShipCountry
FETCH NEXT FROM UpdateOneRowCur INTO @Freight
RETURN @@Identity
DECLARE @Ret int
EXECUTE @Ret = @Freight;
--EXECUTE @Ret = spUpateOrder --'alfki', 7, '1/1/2013', null, null, 1
, null;
IF @ret = 0
PRINT 'error!';
ELSE
PRINT 'OrderId entered: ' + CAST(@ret as varchar);
CLOSE UpdateOneRowCur
DEALLOCATE UpdateOneRowCur
END;
GO
Declare @Ret int
EXEC @Ret = spUpateOrder 'alfki', 7, '1/1/2013', null, null, 1, 25.99;
GO
[/代码]
这段代码确实一次更改了所有行,但我只希望它更改它找到的第一行,然后在下次我 运行 存储过程时更改它找到的第二行。不确定该怎么做?注意:为了测试它,我创建了一些具有相同运费值 25.99 的新行。
答案:
这是我每次执行存储过程时只更改一行的方法:(这确实有效!)
[code]
--============== UPdate only one row ===============--
CREATE PROCEDURE uspUpdateOrder
@Freight money --Testing.
AS
/*
Created by: Chris Singleton
02/26/2017
Updates each row that has 25.99 where the customer's name is 'alfki'.
*/
BEGIN
--DECLARE @Freight
UPDATE top (1) Northwind.dbo.Orders
SET Freight = @Freight + .1
WHERE CustomerID = 'alfki' AND Freight = 25.99
END;
--============ Call the Stored Procedure =============--
GO
-- the call:
Declare @Ret int
EXEC @Ret = uspUpdateOrder 25.99;
If @ret = 0
print 'error!';
else
print 'OrderId entered: ' + cast(@ret as varchar);
DROP PROCEDURE uspUpdateOrder
GO
SELECT * FROM [Northwind].[dbo].[Orders] WHERE CustomerID = 'alfki'
--====================================--
[/code]
您的代码中存在多个问题:
- 您正在将“@Freight”作为参数传递。在您的示例中,您为此变量分配了一个值 25.99
- 然后将变量的值增加 0.1 (SET @Freight = @Freight + .1)。因此,在您的示例中,变量的值将为 26.09
- 然后你 运行 查询并用你的查询结果覆盖 @Freight 的值 (FETCH NEXT FROM UpdateOneRowCur INTO @Freight)。此时,步骤1和2完全多余,因为你正在覆盖之前的内容。
- 您正在使用一个循环,并且在您的循环中,您不断从查询的结果集中读取一行并覆盖@Freigh 的值并调用更新过程。
如果你只需要更新第一行,那么你可以这样写:
SELECT top 1 @Freight = Freight FROM [NorthWind].[dbo].[Orders] -- WHERE Freight = NULL
WHERE CustomerID = 'alfki' AND Freight < 30.00 AND Freight IS NOT NULL
SET @Freight = @Freight + .1 -- I'm not sure if you realy want to do this or not
我在您的查询中所做的更改是我只返回一行 (select top 1
),同时分配 @Freight
您真的不需要任何游标或循环。
Sparrow 在某种程度上是正确的,我不需要光标来进行编码,所以我给了 Sparrow 分数,但是为了使用过滤器专注于一行,您可以这样做。
[Code]
--============== UPdate only one row ===============--
CREATE PROCEDURE uspUpdateOrder
@Freight money --Testing.
AS
/*
Created by: Chris Singleton
02/26/2017
Updates each row that has 25.99 where the customer's name is 'alfki'.
*/
BEGIN
--DECLARE @Freight
UPDATE top (1) Northwind.dbo.Orders
SET Freight = @Freight + .1
WHERE CustomerID = 'alfki' AND Freight = 25.99
END;
--============ Call the Stored Procedure =============--
GO
-- the call:
Declare @Ret int
EXEC @Ret = uspUpdateOrder 25.99;
If @ret = 0
print 'error!';
else
print 'OrderId entered: ' + cast(@ret as varchar);
DROP PROCEDURE uspUpdateOrder
GO
SELECT * FROM [Northwind].[dbo].[Orders] WHERE CustomerID = 'alfki'
--====================================--
[/Code]
注意:您可以结合使用更新子句 TOP (1) 和 where 子句作为过滤器来关注该行。这个作品不错!