2012-02-08 67 views
0

這是我第一次使用IF Exists和BEGIN TRANSACTION。我在'If Exists'部分'附近有錯誤的語法')和'End'末尾的'Transaction'附近的語法錯誤。如果重複的條目存在,並且如果存在錯誤回滾事務並返回錯誤或返回@@ RowCount,我不知道應該選擇哪一個,這樣可能會有人糾正我的過程並使其請對其進行任何調整。SQL事務重複條目

BEGIN TRANSACTION 
IF EXISTS (SELECT * FROM Forums WHERE Title = @Title) 
    BEGIN 
     RAISERROR ('Duplicate Entry', 16, 1) 
    END 
ELSE 
    BEGIN 
     INSERT INTO Forums(AddedBy, AddedDate, Title, Description, 
       ParentID, Moderated, ImageUrl, UpdatedBy, UpdatedDate, Active, Importance) 
     VALUES(@AddedBy, @AddedDate, @Title, null, null, False, null, null, null, True, 0) 
     RETURN @@ROWCOUNT 
    END 


IF @@ERROR <> 0 
    BEGIN 
     ROLLBACK TRANSACTION 
     RETURN @@ERROR 
    END 

END TRANSACTION 
+0

兩個快速意見:(1)'END TRANSACTION'無效。 (2)您應該使用輸出參數而不是'RETURN'將'@@ ROWCOUNT'發送回客戶端。 'RETURN'用於錯誤代碼,而不是數據。如果您只想返回插入成功,則返回1或某個特殊數字以指示成功。 – 2012-02-08 02:45:08

回答

1

你不需要交易,除非你想強制隔離級別,或者如果你有一個以上的更新/插入/刪除語句,你需要推出他們都回來,如果一個錯誤情況發生,或提交所有這些,如果一切順利,在

示例代碼

,你有一個INSERT語句甚至不會去執行,所以你有什麼可回滾

DECLARE @InsertedRows INT = 0 

INSERT INTO Forums(AddedBy, AddedDate, Title, Description, ParentID, 
    Moderated, ImageUrl, UpdatedBy, UpdatedDate, Active, Importance) 
SELECT @AddedBy, @AddedDate, @Title, null, null, 'False', null, null, null, 'True', 0 
WHERE NOT EXISTS (SELECT * FROM Forums WHER Title = @Title) 


SET @InsertedRows = @@ROWCOUNT 

IF @InsertedRows = 1 
    RETURN 1 
ELSE 
    RETURN -1 
+0

謝謝你。爲什麼我得到了無效的列False和True – ONYX 2012-02-08 01:45:16

+0

@KDM不知道我知道你的意思是通過獲得無效的列False和True – 2012-02-08 01:48:29

+0

我只是把引號放在它們周圍,它工作得很好,謝謝你的回答。但是如果我在插入語句中發生了錯誤怎麼辦?那麼你可以提供更新給你回答 – ONYX 2012-02-08 01:51:20

0
BEGIN TRANSACTION 

    IF EXISTS (SELECT * FROM Forums WHERE Title = @Title) 
    BEGIN 
     RAISERROR ('Duplicate Entry', 16, 1) 
    END 
    ELSE 
    BEGIN 
      INSERT INTO Forums(AddedBy, AddedDate, Title, Description, ParentID, 
       Moderated, ImageUrl, UpdatedBy, UpdatedDate, Active, Importance) 
      VALUES(@AddedBy, @AddedDate, @Title, null, null, False, null, null, null, True, 0) 

      COMMIT TRANSACTION 

     RETURN @@ROWCOUNT 
    END 

    IF @@ERROR <> 0 
    BEGIN 
     ROLLBACK TRANSACTION 
     RETURN @@ERROR 
    END 
0

你不」真的需要這筆交易。單行插入要麼成功要麼失敗(在這種情況下@@ROWCOUNT只會返回1)。如果你在標題欄上有一個唯一的約束(顯然你應該擁有這個約束),你不需要首先檢查,儘管這樣做可能會更有效率(我將不得不執行一些測試來確認,但我很確定錯誤機制是相當昂貴的)。反正這裏是在什麼情況下,錯誤處理應該出問題以外的其他違反約束的標題版本:

IF EXISTS (SELECT 1 FROM dbo.Forums WHERE Title = @Title) 
BEGIN 
    RAISERROR('Duplicate entry', 16, 1); 
    RETURN 2627; -- key constraint violation 
END 
ELSE 
BEGIN 
    BEGIN TRY 
     INSERT dbo.Forums 
     (
      AddedBy, AddedDate, Title, 
      Description, ParentID, 
      Moderated, ImageUrl, UpdatedBy, 
      UpdatedDate, Active, Importance 
     ) 
     SELECT 
      @AddedBy, 
      @AddedDate, 
      @Title, 
      NULL, NULL, 
      'False', -- did you mean 0? 
      NULL, NULL, NULL, 
      'True', -- did you mean 1? 
      0; 

     RETURN 1; 
    END TRY 
    BEGIN CATCH 
     DECLARE @msg NVARCHAR(4000) = 'Insert failed ' + ERROR_MESSAGE(); 
     RAISERROR(@msg, 16, 1); 
     RETURN ERROR_NUMBER(); 
    END CATCH 
END 
+0

我只是提出了一個不同的解決方案,它不需要數據庫端的所有這些錯誤處理邏輯,而是在域邏輯中處理它。這種情況很簡單,你可以設法插入或者不插入。 – 2012-02-08 13:35:02

+0

是否有可能你在ELSE塊中結束,同時有人插入一個具有相同標題的記錄?現在會發生什麼?也許你需要使用隔離級別來防止這種情況發生。 OH甜蜜的複雜性! – 2012-02-08 13:36:31

+0

這就是額外的'TRY' /'CATCH'邏輯的要點。如果其他人用相同的標題擊敗你,只有你們中的一個會贏。我認爲併發隔離級別不會解決這個問題 - 您仍然有兩個用戶嘗試插入相同的標題,只有一個用戶可以執行此操作。 – 2012-02-08 14:40:05