SQL:将变量设置为存储过程中的单元格值
SQL: Set variable to a cell value inside a stored procedure
我正在尝试将来自一个 table 的单个单元格值存储在一个变量中(在存储过程中),因此我可以使用它来编辑另一个 table 中的值,但是我不断收到 MSG 201:
Procedure or function 'spBookReturn' expects parameter '@bookID', which was not supplied.
每次我尝试 运行 应该发生的 sp:
CREATE PROC spBookReturn
@loanID UNIQUEIDENTIFIER,
@bookID UNIQUEIDENTIFIER OUTPUT
AS
BEGIN
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial SET returned = 1, returnedDate = GETDATE();
SET @bookID = (SELECT TOP 1 bookID FROM BorrowedMaterial WHERE loanID = @loanID ORBER BY returnedDate);
UPDATE Books SET nHome = nHome + 1 WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END;
EXEC spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F'
有谁知道为什么我定义 @bookID 变量的方式不起作用以及我如何才能让它起作用?
谢谢。
编辑:
我有两个 tables:BorrowedMaterial
,其中包括属性 loanID, bookID, returned, returnedDate
和其他一些不相关的属性。
另一个 table 是 Books
,它包括 bookID, nHome
但不包括 loanID
。
因此,通过仅提供 loanID
作为输入,我想更新 nHome
。我正在尝试获取 bookID
,因为这是两个属性唯一的共同点,这就是问题发生的地方。
旁注:我错误地删除了它生成的变量@custID。
declare @bookID UNIQUEIDENTIFIER;
declare @custID UNIQUEIDENTIFIER;
declare @InResult;
exec @InResult= spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F',@bookID,@custID;
select @bookID,@custID;
看来,你需要这样的东西
过程的所有 参数都是输入参数。如果您将参数声明为 OUTPUT
参数,它仍然是输入参数,如果它没有默认值,则必须提供 。
如果您希望 OUTPUT
参数是可选的,我个人认为这可能很常见,那么请给它们一个默认值。我还在您的过程中添加了一些额外的逻辑,因为您应该在查询中使用 TRY...CATCH
和 ORDER BY
以及 TOP
.
CREATE PROC dbo.spBookReturn @loanID uniqueidentifier,
@bookID uniqueidentifier = NULL OUTPUT,
@custID uniqueidentifier = NULL OUTPUT
AS
BEGIN
BEGIN TRY --If you are using tranasctions, make sure you have a ROLLBACK and THROW for errors
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial
SET returned = 1,
returnedDate = GETDATE()
WHERE loanID = @loanID;
/*
UPDATE BorrowedMaterial
SET returnedDate = GETDATE()
WHERE loanID = @loanID;
*/
SET @bookID = (SELECT TOP 1 bookID
FROM BorrowedMaterial
WHERE loanID = @loanID
ORDER BY ???); --A TOP should have an ORDER BY
UPDATE Books
SET nHome = nHome + 1
WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION tBookReturn;
THROW;
END CATCH;
END;
然后您可以按原样执行该过程,而无需传递 @bookID
和 @custID
。当然,如果不这样做,它们的值将在调用语句中“丢失”。如果您需要它们,那么也可以在 EXEC
:
中传递它们的值
DECLARE @bookID uniqueidentifier, @CustID uniqueidentifier;
EXEC dbo.spBookReturn @loanID, @bookID OUTPUT, @CustID OUTPUT;
--SELECT @bookID, @CustID;
我对你要找的东西的看法。因为在单个事务中有多个 DML 语句(2 个更新),所以 XACT_ABORT ON 选项可确保完全回滚。此外,CATCH 块中的 THROW 位于 ROLLBACK 之前,以保留 SQL 生成的错误元数据。在执行过程之前,输出变量被声明并放置在参数列表中(这个遗漏是导致初始错误的原因)。
drop proc if exists dbo.spBookReturn;
go
CREATE PROC dbo.spBookReturn
@loanID uniqueidentifier,
@bookID uniqueidentifier OUTPUT,
@custID uniqueidentifier OUTPUT
AS
set nocount on;
set xact_abort on;
BEGIN TRANSACTION tBookReturn
BEGIN TRY
declare @ins_bm table(book_id uniqueidentifier,
cust_id uniqueidentifier);
UPDATE BorrowedMaterial
SET returned = 1,
returnedDate = GETDATE()
output inserted.book_id, inserted.cust_id into @ins_bm
WHERE loanID = @loanID;
if @@rowcount=0
begin
select @bookID=0,
@custID=0;
throw 50000, 'No update performed', 1;
end
else
begin
UPDATE b
SET nHome = nHome + 1
from Books b
WHERE exists (select 1
from @ins_bm bm
where b.ID = bm.book_id);
select top(1) @bookID=book_id,
@custID=cust_id
from @ins_bm;
end
COMMIT TRANSACTION tBookReturn;
END TRY
BEGIN CATCH
THROW
ROLLBACK TRANSACTION tBookReturn;
END CATCH;
go
declare @bookID UNIQUEIDENTIFIER;
declare @custID UNIQUEIDENTIFIER;
declare @InResult int;
exec @InResult=spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F', @bookID output, @custID output;
select @bookID, @custID;
感谢@Larnu,我发现唯一缺少的是第 3 行的 =
(感谢@charlieface,我也稍微清理了我的代码):
CREATE PROC spBookReturn
@loanID UNIQUEIDENTIFIER,
@bookID UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial SET returned = 1, returnedDate = GETDATE();
SET @bookID = (SELECT TOP 1 bookID FROM BorrowedMaterial WHERE loanID = @loanID
ORDER BY returnedDate);
UPDATE Books SET nHome = nHome + 1 WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END;
EXEC spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F'
我正在尝试将来自一个 table 的单个单元格值存储在一个变量中(在存储过程中),因此我可以使用它来编辑另一个 table 中的值,但是我不断收到 MSG 201:
Procedure or function 'spBookReturn' expects parameter '@bookID', which was not supplied.
每次我尝试 运行 应该发生的 sp:
CREATE PROC spBookReturn
@loanID UNIQUEIDENTIFIER,
@bookID UNIQUEIDENTIFIER OUTPUT
AS
BEGIN
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial SET returned = 1, returnedDate = GETDATE();
SET @bookID = (SELECT TOP 1 bookID FROM BorrowedMaterial WHERE loanID = @loanID ORBER BY returnedDate);
UPDATE Books SET nHome = nHome + 1 WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END;
EXEC spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F'
有谁知道为什么我定义 @bookID 变量的方式不起作用以及我如何才能让它起作用?
谢谢。
编辑:
我有两个 tables:BorrowedMaterial
,其中包括属性 loanID, bookID, returned, returnedDate
和其他一些不相关的属性。
另一个 table 是 Books
,它包括 bookID, nHome
但不包括 loanID
。
因此,通过仅提供 loanID
作为输入,我想更新 nHome
。我正在尝试获取 bookID
,因为这是两个属性唯一的共同点,这就是问题发生的地方。
旁注:我错误地删除了它生成的变量@custID。
declare @bookID UNIQUEIDENTIFIER;
declare @custID UNIQUEIDENTIFIER;
declare @InResult;
exec @InResult= spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F',@bookID,@custID;
select @bookID,@custID;
看来,你需要这样的东西
过程的所有 参数都是输入参数。如果您将参数声明为 OUTPUT
参数,它仍然是输入参数,如果它没有默认值,则必须提供 。
如果您希望 OUTPUT
参数是可选的,我个人认为这可能很常见,那么请给它们一个默认值。我还在您的过程中添加了一些额外的逻辑,因为您应该在查询中使用 TRY...CATCH
和 ORDER BY
以及 TOP
.
CREATE PROC dbo.spBookReturn @loanID uniqueidentifier,
@bookID uniqueidentifier = NULL OUTPUT,
@custID uniqueidentifier = NULL OUTPUT
AS
BEGIN
BEGIN TRY --If you are using tranasctions, make sure you have a ROLLBACK and THROW for errors
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial
SET returned = 1,
returnedDate = GETDATE()
WHERE loanID = @loanID;
/*
UPDATE BorrowedMaterial
SET returnedDate = GETDATE()
WHERE loanID = @loanID;
*/
SET @bookID = (SELECT TOP 1 bookID
FROM BorrowedMaterial
WHERE loanID = @loanID
ORDER BY ???); --A TOP should have an ORDER BY
UPDATE Books
SET nHome = nHome + 1
WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION tBookReturn;
THROW;
END CATCH;
END;
然后您可以按原样执行该过程,而无需传递 @bookID
和 @custID
。当然,如果不这样做,它们的值将在调用语句中“丢失”。如果您需要它们,那么也可以在 EXEC
:
DECLARE @bookID uniqueidentifier, @CustID uniqueidentifier;
EXEC dbo.spBookReturn @loanID, @bookID OUTPUT, @CustID OUTPUT;
--SELECT @bookID, @CustID;
我对你要找的东西的看法。因为在单个事务中有多个 DML 语句(2 个更新),所以 XACT_ABORT ON 选项可确保完全回滚。此外,CATCH 块中的 THROW 位于 ROLLBACK 之前,以保留 SQL 生成的错误元数据。在执行过程之前,输出变量被声明并放置在参数列表中(这个遗漏是导致初始错误的原因)。
drop proc if exists dbo.spBookReturn;
go
CREATE PROC dbo.spBookReturn
@loanID uniqueidentifier,
@bookID uniqueidentifier OUTPUT,
@custID uniqueidentifier OUTPUT
AS
set nocount on;
set xact_abort on;
BEGIN TRANSACTION tBookReturn
BEGIN TRY
declare @ins_bm table(book_id uniqueidentifier,
cust_id uniqueidentifier);
UPDATE BorrowedMaterial
SET returned = 1,
returnedDate = GETDATE()
output inserted.book_id, inserted.cust_id into @ins_bm
WHERE loanID = @loanID;
if @@rowcount=0
begin
select @bookID=0,
@custID=0;
throw 50000, 'No update performed', 1;
end
else
begin
UPDATE b
SET nHome = nHome + 1
from Books b
WHERE exists (select 1
from @ins_bm bm
where b.ID = bm.book_id);
select top(1) @bookID=book_id,
@custID=cust_id
from @ins_bm;
end
COMMIT TRANSACTION tBookReturn;
END TRY
BEGIN CATCH
THROW
ROLLBACK TRANSACTION tBookReturn;
END CATCH;
go
declare @bookID UNIQUEIDENTIFIER;
declare @custID UNIQUEIDENTIFIER;
declare @InResult int;
exec @InResult=spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F', @bookID output, @custID output;
select @bookID, @custID;
感谢@Larnu,我发现唯一缺少的是第 3 行的 =
(感谢@charlieface,我也稍微清理了我的代码):
CREATE PROC spBookReturn
@loanID UNIQUEIDENTIFIER,
@bookID UNIQUEIDENTIFIER = NULL OUTPUT
AS
BEGIN
BEGIN TRANSACTION tBookReturn
UPDATE BorrowedMaterial SET returned = 1, returnedDate = GETDATE();
SET @bookID = (SELECT TOP 1 bookID FROM BorrowedMaterial WHERE loanID = @loanID
ORDER BY returnedDate);
UPDATE Books SET nHome = nHome + 1 WHERE ID = @bookID;
COMMIT TRANSACTION tBookReturn;
END;
EXEC spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F'