Sql-Server

在表上添加 PERIOD FOR SYSTEM_TIME 失敗

  • January 11, 2022

我有:

  • 包含現有數據的表
  • 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));

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