在表上添加 PERIOD FOR SYSTEM_TIME 失敗
我有:
- 包含現有數據的表
- SQL Server 2016 SP1
- SQL Server 管理工作室 17.5
我正在使用以下語句使我的表成為臨時表:
ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups] ADD [SysStartTime] DATETIME2(0) GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysStart DEFAULT GETUTCDATE() ,[SysEndTime] DATETIME2(0) GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysEnd DEFAULT CONVERT(DATETIME2(0), '9999-12-31 23:59:59'), PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime]); ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.AnalysisCustomRollupsV2JoinGroupsChanges));
問題:
在我的本地 SQL 實例上,我有很多數據庫;很奇怪,查詢在其中一些上成功執行,而在其中一些上它給了我以下錯誤:
消息 13542,級別 16,狀態 0,第 51 行在表 ‘dbo.AnalysisCustomRollupsV2JoinGroups’ 上添加 PERIOD FOR SYSTEM_TIME 失敗,因為有打開的記錄的開始時間設置為將來的值。
有時,當我調試/執行查詢時,初始查詢會成功執行。
我讀到,這可能是因為我在表中有現有數據。所以,我改變了這樣的邏輯:
- 創建緩衝區表並用所有記錄填充它
- 從原始表中刪除記錄
- 創建臨時表
- 將記錄移回並刪除緩衝表
同樣,在某些數據庫上可以,而在其他數據庫上則不行。試圖解決這個問題,我發現了以下內容:
對於 StartDate,我指定了目前的 UTC 日期——這可以是任何不在未來的日期和時間,但請注意它應該是 UTC 日期和時間。如果我嘗試使用 GETDATE,因為我目前在英國夏令時,我會收到以下錯誤:Msg 13542, Level 16, State 0, Line 51 ADD PERIOD FOR SYSTEM_TIME on table ‘TestAudit.dbo.SomeData’失敗,因為有打開的記錄將期初設置為將來的值。
以上是什麼意思?我需要更改機器時間嗎?或者因為我的本地機器不是UTC時間我有時會收到這個錯誤?
我想我已經找到了解決問題的方法,但我不會接受這個作為答案,因為我無法解釋導致問題的原因並保證這將在任何時候起作用。經過大量測試後找到了修復,如果有人能在這裡帶來更多的光線,我會很高興。
我從來沒有
datetime2
精確地使用過。所以,我回到了這種格式的來源datetime2(0)
——Alter Non-Temporal Table to be System-Versioned Temporal Table。與我一直使用的腳本的唯一區別是日期時間函式。我使用GETUTCDATE()
過,因為我不需要對datetime(0)
(2018-03-15 07:21:02
例如)如此精確,在範例中它是SYSUTCDATETIME()
. 所以,我改變了它。我創建了一個腳本,如果存在則刪除數據庫,從備份中恢復數據庫,然後循環執行我的程式碼(正如我所說,我有時會收到錯誤,並且很難重現它)。
我已經多次執行腳本,但失敗的次數不同(有時為 70%,有時為 50%,有時低於):
我發現這個為什麼 GETUTCDATE 早於 SYSDATETIMEOFFSET?討論新舊日期時間函式之間的差異。然後建構以下查詢:
DECLARE @UTC DATETIME2(0) = GETUTCDATE(); DECLARE @SYSUTC DATETIME2(0) = SYSUTCDATETIME(); WHILE DATEPART(SECOND, @UTC) = DATEPART(SECOND, @SYSUTC) BEGIN; SET @UTC = GETUTCDATE(); SET @SYSUTC = SYSUTCDATETIME(); END; SELECT @UTC AS [UTC] ,@SYSUTC AS [SYS UTC] ,DATEPART(SECOND, @UTC) AS [UTC sec] ,DATEPART(SECOND, @SYSUTC) AS [SYS UTC sec] ,CASE WHEN @UTC < @SYSUTC THEN 1 ELSE 0 END AS [TimeTravelPossible] ,CONVERT(DATETIME2(0), @UTC) AS [UTC date] ,CONVERT(DATETIME2(0), @SYSUTC) AS [SYS UTC date] ,IIF(CONVERT(DATETIME2(0), @UTC) = CONVERT(DATETIME2(0), @SYSUTC), 1, 0) AS [Are The Same];
我只是想檢查是否可以
datetime2(0)
使用 sys 而不是 sys 日期時間函式獲得不同的日期。當然這是可能的。也許,引擎正在進行的檢查正在執行類似的操作,將其目前日期與我的新日期進行比較,這導致了錯誤 -
open records with start of period set to a value in the future.
我已經像這樣更改了腳本並在昨晚執行了 1000 次 - 沒有產生錯誤。所以,我相信我已經解決了這個特定問題,但我不能確定。
ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups] ADD [SysStartTime] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysStart DEFAULT SYSUTCDATETIME() ,[SysEndTime] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysEnd DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'), PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime]); ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.AnalysisCustomRollupsV2JoinGroupsChanges));