Sql-Server
如果更新語句在 SP 中失敗,SQL Server 2000 是否應該拋出錯誤?
我正在對 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 上重現。