簡體   English   中英

T-SQL If語句問題

[英]T-SQL If Statement issue

我有2個表: dbo.Videosdbo.Checkouts
dbo.Videos表包含視頻列表,而dbo.Checkouts表則跟蹤已簽出的視頻。
我的TSQL命令的目標是在dbo.Checkouts表中插入新行,包括VideoIdUserIdCheckoutDate
一旦成功,我當時想更新dbo.Videos和遞減TotalCopies基於列值VideoID ,如果該值大於0的唯一選擇。
如果小於0,我想拋出一個異常。
兩個表中的VideoID通過外鍵鏈接。
但是,我在下面的語句中包含的IF語句引發錯誤。

INSERT INTO dbo.Checkouts (VideoId, UserId, CheckoutDate)
VALUES (32, 'b0281f0d-8398-4a27-ba92-828bfaa9f90e', CURRENT_TIMESTAMP)

IF (SELECT TotalCopies FROM dbo.Videos WHERE VideoId = 32) > 0
UPDATE dbo.Videos SET
TotalCopies = TotalCopies - 1
WHERE VideoID = 32

你已經倒退了。
而不是增加一個記錄的Checkouts ,然后測試,如果你有在視頻Videos ,你需要首先檢查你有一個副本,你可以退房。
就像您要從任何商店購買商品時一樣-首先您將產品下架,然后才付款。
如果產品不在貨架上,則無需您付款。

第一版

您至少需要三個步驟才能正確執行:
首先,檢查是否有要簽出的副本。
如果沒有,則您什么也不做,只需返回一條消息,指出沒有免費副本可以結帳。
如果有副本,則需要更新Video表(TotalCopies-= 1),最后-您需要將記錄插入到checkouts

這里最重要的是,如果這些步驟中的任何一個失敗,那么所有這些都將失敗-例如,如果由於某種原因您無法將行插入checkouts ,則必須還原對Video表所做的更新,因為您可以無法完成該過程。

這是您需要將整個流程包裝在事務中的第一個原因。
您需要進行交易的第二個原因是要避免測試之間是否存在競爭情況(如果有要結帳的副本)和video表的更新。 您可以在Dan Guzman的有關條件INSERT / UPDATE Race Condition的博客文章中閱讀有關它的更多信息。

這么說了之后,讓我們展示一些代碼:

CREATE PROCEDURE VideoCheckout
(
     @VideoId int, 
     @UserId uniqueIdentifier,
     @Success bit OUTPUT
)
AS

    SET XACT_ABORT ON 

    SET @Success = 0 

    BEGIN TRANSACTION
    BEGIN TRY

        DECLARE @NumberOfCopies int
        SET @NumberOfCopies = ISNULL(
            (
                SELECT TotalCopies
                FROM dbo.Videos WITH (UPDLOCK, HOLDLOCK)
                WHERE VideoId = @VideoId
            )
            , 0)

        IF @NumberOfCopies > 0
        BEGIN

            UPDATE dbo.Videos
            SET TotalCopies = TotalCopies - 1
            WHERE VideoId = @VideoId;

            INSERT INTO dbo.Checkouts (VideoId, UserId, CheckoutDate)
            VALUES (@VideoId, @UserId, CURRENT_TIMESTAMP)

            SET @Success = 1
        END

        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION
    END CATCH

GO

更新-使用@@rowcount版本:

SQL Server的@@Rowcount全局變量返回生效的行數(通常,鏈接中記錄了一些例外情況)-使用它可以將測試部分與更新部分統一-讓SQL Server報告更新是否生效沒有的任何行。 這使您可以編寫更簡單的SQL,並可能具有更好的性能。

CREATE PROCEDURE VideoCheckout
(
     @VideoId int, 
     @UserId uniqueIdentifier,
     @Success bit OUTPUT
)
AS

    SET XACT_ABORT ON 

    SET @Success = 0 

    BEGIN TRANSACTION
    BEGIN TRY

        UPDATE dbo.Videos
        SET TotalCopies = TotalCopies - 1
        WHERE VideoId = @VideoId
        AND TotalCopies > 0;

        IF @@ROWCOUNT > 0 
        BEGIN

            INSERT INTO dbo.Checkouts (VideoId, UserId, CheckoutDate)
            VALUES (@VideoId, @UserId, CURRENT_TIMESTAMP)

            SET @Success = 1

        END

        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION
    END CATCH

GO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM