Sql-Server

如果更新語句在 SP 中失敗,SQL Server 2000 是否應該拋出錯誤?

  • October 19, 2018

我正在對 SQL Server 2000 上的一個問題進行故障排除,在該問題中,儲存過程中的更新語句似乎失敗,並且檢查@@ERROR <> 0沒有擷取它,因此事務已送出。

下面是程式碼的精簡版。我刪除了很多細節和專有資訊,但這是它的要點。這段程式碼每天都執行了幾個月並產生了預期的結果,除了上週的一次,其中聲明:

UPDATE /*app table*/ 
  set dateprocessed = @currentDate 
where jobname = 'Job_' 
      + REPLACE(CONVERT(VARCHAR(10), GETDATE(), 101), '/', '') 
      + LEFT(REPLACE(CONVERT(VARCHAR(8), GETDATE(), 108), ':', ''), 4) 
      + '_' 
      + (SELECT Description FROM #tempTable1 WHERE id = @i)

…顯然實際上並沒有更新引用的表,但是執行了其餘程式碼並送出了事務。

如果更新語句沒有成功完成,它是否應該被我的@@ERROR檢查發現?

DECLARE @startTime DATETIME,
       @procedureName NVARCHAR(50),
       @i INT,
       @currentDate DATETIME,
       @minimumLetterCount INT;

SET @startTime = GETDATE();
SET @procedureName = (SELECT OBJECT_NAME(@@PROCID));
SET @i = 1;
SET @currentDate = GETDATE();

BEGIN TRANSACTION
   IF (--constraints are met)
   BEGIN
       IF OBJECT_ID('tempdb.dbo.#tempTable1') IS NOT NULL  
           DROP TABLE #tempTable1;

       IF OBJECT_ID('tempdb.dbo.##globalTempTable1') IS NOT NULL  
           DROP TABLE ##globalTempTable1;

       CREATE TABLE #tempTable1 (
           --columns defined here
       );

       CREATE TABLE ##globalTempTable1 (
           --columns defined here
       );

       INSERT INTO #tempTable1
           EXEC /*SP name*/

       --Process pending items by ID
       WHILE (@i <= (SELECT COUNT(*) FROM #tempTable1))
       BEGIN
           DECLARE @CurrentItemID VARCHAR(3);
           DECLARE @CurrentJobName VARCHAR(100);
           SELECT @CurrentItemID = (SELECT LetterID FROM #tempTable1 WHERE id = @i);
           SELECT @CurrentJobName = 'Job_' + REPLACE(CONVERT(VARCHAR(10), GETDATE(), 101), '/', '') + LEFT(REPLACE(CONVERT(VARCHAR(8), GETDATE(), 108), ':', ''), 4) + '_' + (SELECT Description FROM #tempTable1 WHERE id = @i);
           EXEC /*SP name*/ @TableID = @CurrentItemID, @ThroughDate = @currentDate, @JobName = @CurrentJobName, @SeedItem = 1;

           INSERT INTO ##globalTempTable1
           SELECT --some data from other tables into this temp table

           UPDATE /*app table*/ set dateprocessed = @currentDate where jobname = 'Job_' + REPLACE(CONVERT(VARCHAR(10), GETDATE(), 101), '/', '') + LEFT(REPLACE(CONVERT(VARCHAR(8), GETDATE(), 108), ':', ''), 4) + '_' + (SELECT Description FROM #tempTable1 WHERE id = @i)

           UPDATE l
               SET l.LinkedValue1 = lb.LinkedValue2
               FROM ##globalTempTable1 l
               INNER JOIN (SELECT UniqueID, SUM(CAST(REPLACE(REPLACE(REPLACE(REPLACE(value, '$', ''), ',', ''), '(', ''), ')', '') AS DECIMAL(12,2))) AS LinkedValue2 FROM ##globalTempTable1 GROUP BY UniqueID) lb ON l.UniqueID = lb.UniqueID;

           SET @i = @i + 1;

       END

   END

IF @@ERROR <> 0
   BEGIN
       ROLLBACK TRANSACTION

       --log failure
       INSERT INTO JobLog (jobName, success, startTime, endTime) VALUES (@procedureName, 0, @startTime, GETDATE());
   END
ELSE
   BEGIN
       COMMIT TRANSACTION

       --log success
       INSERT INTO JobLog (jobName, success, startTime, endTime) VALUES (@procedureName, 1, @startTime, GETDATE());
   END

--Cleanup temp tables
IF OBJECT_ID('tempdb.dbo.#tempTable1') IS NOT NULL  
   DROP TABLE #tempTable1;

IF OBJECT_ID('tempdb.dbo.##globalTempTable1') IS NOT NULL  
   DROP TABLE ##globalTempTable1;

我懷疑發生的事情是找不到您希望找到的行,可能是因為作業名稱已關閉,或者因為GETDATE()被多次評估將每隔一段時間在不同的秒內進行評估。所以我不太確定為什麼你要處理的每個時間戳都有一份新工作,但由於這個原因它不匹配當然是合理的(只是很難在現代版本上重現)。看看 #tmp 是否被填充:

SET NOCOUNT ON;
CREATE TABLE #tmp(i int);
GO

INSERT #tmp(i) SELECT o4.id + 0
FROM sysobjects AS o0, sysobjects AS o1,  syscolumns AS o2, 
     sysobjects AS o3, syscomments AS o4, syscolumns AS o5
WHERE CONVERT(char(8), getdate(), 108) <> CONVERT(char(8), getdate(), 108);
GO 1000

SELECT i FROM #tmp;
GO

DROP TABLE #tmp;

如果您得到一行或多行,那麼您知道 getdate() 的評估方式不同。如果你不這樣做,那麼這次你很幸運。

為避免這種可能性,請分配getdate()給一個變數:

UPDATE /*app table*/ 
  set dateprocessed = @currentDate 
where jobname = 'Job_' 
      + REPLACE(CONVERT(VARCHAR(10), GETDATE(), 101), '/', '') 
      + LEFT(REPLACE(CONVERT(VARCHAR(8), GETDATE(), 108), ':', ''), 4) 
      + '_' 
      + (SELECT Description FROM #tempTable1 WHERE id = @i);

請記住(不僅是您,還有未來的讀者),請在 SQL Server 2000 上嘗試此操作。如果沒有記錯的話,舊版本更容易受到此影響,並且您不太可能在現代 SQL Server 上重現。

引用自:https://dba.stackexchange.com/questions/220591