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...CATCHORDER 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'