【问题标题】:SQL: Set variable to a cell value inside a stored procedureSQL:将变量设置为存储过程中的单元格值
【发布时间】:2021-01-27 13:23:31
【问题描述】:

我正在尝试将一个表中的单个单元格值存储在一个变量中(在存储过程中),因此我可以使用它来编辑另一个表中的值,但我不断收到 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 变量的方式不起作用以及如何使它起作用?

谢谢。

编辑: 我有两个表:BorrowedMaterial,其中包括属性loanID, bookID, returned, returnedDate 和其他一些不相关的。 另一个表是Books,它包括bookID, nHome,但不包括loanID

所以通过只提供loanID 作为输入,我想更新nHome。我试图抓住bookID,因为这是这两个属性唯一的共同点,这就是问题发生的地方。

旁注:我删除了它错误产生的变量@custID。

【问题讨论】:

    标签: sql tsql variables stored-procedures


    【解决方案1】:
    过程的

    所有参数都是输入参数。如果您将参数声明为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;
    

    【讨论】:

    • 可以先合并两个updates。您也可以合并select 和以下update
    • 是的,他们可以,@Charlieface。当我解决一些更基本的问题时,我错过了;)
    • 只是想:如果@loanId 是唯一的(看起来是),那么您就不需要@bookId。但如果不是,那么整个 update 就没有意义
    • @Larnu 感谢您的回答。我没有为变量设置默认值的原因是 1:到目前为止它一直工作正常,更重要的是 2 我一做就得到不正确的语法错误。我试图完全复制您的代码,但语法错误出现在= 的正下方,说它期待AS, FOR or WITH。 @Charlieface 我已经更新了这个问题,解释了为什么我什至在@bookID 上浪费时间:)
    • “它一直工作到现在” 那你之前一定是在传递参数,@Kudue。 “我一做就收到不正确的语法错误” 那你做的和我上面做的不一样。
    【解决方案2】:
     declare @bookID UNIQUEIDENTIFIER;
     declare @custID UNIQUEIDENTIFIER;
     declare @InResult;
     exec @InResult= spBookReturn '546A444A-3D8D-412E-876D-2053D575B54F',@bookID,@custID;
     select @bookID,@custID;
    

    看来,你需要这样的东西

    【讨论】:

      【解决方案3】:

      我对您正在寻找的内容的看法。由于单个事务中有多个 DML 语句(2 个更新),因此 XACT_ABORT ON 选项可确保完全回滚。此外,CATCH 块中的 THROW 放置在 ROLLBACK 之前,以保留 SQL 生成的错误元数据。在执行 proc 之前声明 OUTPUT 变量并将其放置在参数列表中(这个遗漏是导致初始错误的原因)。

      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;
      

      【讨论】:

        【解决方案4】:

        感谢@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'
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-08-05
          • 2011-06-06
          • 1970-01-01
          • 1970-01-01
          • 2022-01-07
          • 2017-10-06
          • 1970-01-01
          相关资源
          最近更新 更多