Sql-Server

更改臨時表的行為以記錄實際值更改而不是虛擬更新

  • August 23, 2020

目前,我閱讀的有關臨時表的文章將清理的責任推給了應用程式碼。是否可以將臨時表配置為記錄特定列值的更改,而不是在表上呼叫更新語句時?

預期行為的範例:

USE Master;
GO

-- Create test database
CREATE DATABASE [TemporalTables];
GO

USE TemporalTables;
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- Hidden period columns
CREATE TABLE [dbo].[PersonHistory](
   [PersonID] [int] NOT NULL,
   [EmailAddress] [varchar](75) NULL,
   [IsSubscribed] [bit] NULL,
   [SysStartTime] datetime2  NOT NULL,  
   [SysEndTime] datetime2 NOT NULL
);    

CREATE CLUSTERED COLUMNSTORE INDEX IX_PersonHistory   
  ON PersonHistory;   
CREATE NONCLUSTERED INDEX IX_PersonHistory_ID_PERIOD_COLUMNS   
  ON PersonHistory (SysEndTime, SysStartTime, PersonID);   
GO   

CREATE TABLE [dbo].[Person](
   [PersonID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
   [EmailAddress] [varchar](75) NULL,
   [IsSubscribed] [bit] NULL,
   [SysStartTime] datetime2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,  
   [SysEndTime] datetime2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
   PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)     
)    
WITH
(   
     SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.PersonHistory)   
);  

-- Current Time UTC
SELECT sysutcdatetime();
-- Value: 2017-03-14 16:11:56.6294004

--Insert Rows
INSERT [dbo].[Person] ([EmailAddress], [IsSubscribed]) VALUES ('SD.Burman@gmail.com', 1);
GO

INSERT [dbo].[Person] VALUES ('RD.Burman@gmail.com', 1);
GO

INSERT [dbo].[Person] ([EmailAddress], [IsSubscribed], [SysStartTime], [SysEndTime])
VALUES ('AR.Rehman@gmail.com', 1, default, default);
GO

-- Query the main table
SELECT *, SysStartTime, SysEndTime
FROM dbo.Person
-- Shows all changes for specific PK (for inserts to show up)
SELECT *, SysStartTime, SysEndTime
FROM dbo.Person
FOR SYSTEM_TIME ALL
where Personid IN (1,2,3);

-- Current Time UTC
SELECT sysutcdatetime();
-- Value: 2017-03-14 16:13:27.0374068

--Update Rows (Actual Updates)
UPDATE [dbo].[Person] SET [EmailAddress] = 'SD.Burman@hotmail.com' WHERE [EmailAddress] = 'SD.Burman@gmail.com';
GO
UPDATE [dbo].[Person] SET [EmailAddress] = 'RD.Burman@hotmail.com' WHERE [EmailAddress] = 'RD.Burman@gmail.com';
GO
--Update Rows (Dummy Update)
UPDATE [dbo].[Person] SET [EmailAddress] = 'AR.Rehman@gmail.com' WHERE [EmailAddress] = 'AR.Rehman@gmail.com';
GO

-- Query the history table
SELECT *
FROM dbo.PersonHistory

-- !!!
-- What I'd want is that the Id = 3 update to not get saved since the data did not change.
-- Also a way I can limit the number of columns I want this behavior on.
-- PersonID    EmailAddress                                                                IsSubscribed SysStartTime                SysEndTime
-- ----------- --------------------------------------------------------------------------- ------------ --------------------------- ---------------------------
-- 1           SD.Burman@gmail.com                                                         1            2017-03-14 16:12:29.5018193 2017-03-14 16:13:27.0374068
-- 2           RD.Burman@gmail.com                                                         1            2017-03-14 16:12:29.5118172 2017-03-14 16:13:27.1484051
-- !!!

強調此行為的類似問題:

沒有時態表時是否會記錄更改?

我正在尋找上述行為的解決方法。

更改數據擷取將能夠處理這個(甚至是自定義觸發器),但我正在探索是否可以獲得具有選擇性歷史記錄的臨時表的好處。

挑戰在於,我們有一個syncdatatime經常接觸列的 ETL 作業,我們希望排除或包含某些列,並且只記錄實際數據值發生變化時,最好使用時態表。

在進一步的潛水中,這似乎目前屬於:管理系統版本化臨時表中歷史數據的保留作為該問題的反動解決方案,而不是先前的配置。

他們提出了三種方法:

  1. 拉伸數據庫
  2. 表分區
  3. 自定義清理腳本

我發現了其他一些不錯的文章,它們部分回答了我的問題,但是,如果我可以在數據創建而不是清理時管理這種行為,我會很高興,所以我會請求更多資訊以防有人擁有它,或者如果這在未來發生變化。

其他文章:

在 SQL Server 2016 時

態表注意事項和限制中管理時態表歷史記錄

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