修改系統版本化時態表中的資料

適用於: SQL Server 2016 (13.x) 和更新版本 Azure SQL DatabaseAzure SQL 受控執行個體Microsoft Fabric 中的 SQL 資料庫

系統版本設定時態表中的資料是使用一般的資料操作語言 (DML) 陳述式來修改,但有一個重要差異:期間資料行的資料是無法直接修改的。 當資料更新時,會設定版本,並且每個更新資料列的前一個版本會入歷史資料表中。 當資料被刪除時,刪除是邏輯的,該列會從目前的資料表移入歷史資料表;資料並不會永久刪除。

插入數據

當您插入新資料時,必須說明 PERIOD 資料行 (如果其不是 HIDDEN)。 您也可以搭配時間表使用分區切換。

插入新資料,並顯示時間期間的資料欄

請如下根據可見的 INSERT 欄位來建構你的 PERIOD 陳述式:

如果您在 INSERT 陳述式中指定資料行清單,則可省略 PERIOD 資料行,因為系統將自動產生這些資料行的值。

-- Insert with column list and without period columns
INSERT INTO [dbo].[Department]
(
    [DeptID],
    [DeptName],
    [ManagerID],
    [ParentDeptID]
)
VALUES (10, 'Marketing', 101, 1);

如果您在 PERIOD 陳述式的資料行清單中指定 INSERT 資料行,就必須將 DEFAULT 指定為其值。

INSERT INTO [dbo].[Department]
(
    DeptID,
    DeptName,
    ManagerID,
    ParentDeptID,
    ValidFrom,
    ValidTo
)
VALUES (11, 'Sales', 101, 1, DEFAULT, DEFAULT);

如果您未在 INSERT 陳述式中指定資料行清單,請為 DEFAULT 資料行指定 PERIOD

-- Insert without a column list and DEFAULT values for period columns
INSERT INTO [dbo].[Department]
VALUES (
    12,
    'Production',
    101,
    1,
    DEFAULT,
    DEFAULT
);

將資料插入含有隱藏期間欄位的資料表

如果將 PERIOD 資料行指定為 HIDDEN,則您不需要說明 PERIOD 陳述式中的 INSERT 資料行。 此行為可確保舊版應用程式在對受益於版本控制的資料表啟用系統版本控制時仍能繼續運作。

CREATE TABLE [dbo].[CompanyLocation]
(
    [LocID] INT IDENTITY (1, 1) NOT NULL PRIMARY KEY,
    [LocName] VARCHAR (50) NOT NULL,
    [City] VARCHAR (50) NOT NULL,
    [ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    [ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo])
)
WITH (SYSTEM_VERSIONING = ON);
GO

INSERT INTO [dbo].[CompanyLocation]
VALUES ('Headquarters', 'New York');

使用 PARTITION SWITCH 插入資料

如果目前的資料表是分割的,你可以用 PARTITION SWITCH 來有效地將資料載入空分割區,或是同時載入多個分割區。

在搭配時態資料表的 PARTITION SWITCH IN 陳述式中使用的暫存資料表必須已定義 SYSTEM_TIME PERIOD,但不需要是時態資料表。 這可確保時態一致性檢查會在資料插入暫存表格期間執行,或是在將 SYSTEM_TIME 期間新增至預先填入暫存表格時執行。

/* Create staging table with period definition for SWITCH IN temporal table */
CREATE TABLE [dbo].[Staging_Department_Partition2]
(
    [DeptID] INT NOT NULL,
    [DeptName] VARCHAR (50) NOT NULL,
    [ManagerID] INT NULL,
    [ParentDeptID] INT NULL,
    [ValidFrom] DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
    [ValidTo] DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
    PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo])
) ON [PRIMARY];

/* Create aligned primary key */
ALTER TABLE [dbo].[Staging_Department_Partition2]
    ADD CONSTRAINT [Staging_Department_Partition2_PK]
        PRIMARY KEY CLUSTERED ([DeptID] ASC) ON [PRIMARY];

/*
Create and enforce constraints for partition boundaries.
Partition 2 contains rows with DeptID > 100 and DeptID <=200
*/
ALTER TABLE [dbo].[Staging_Department_Partition2] WITH CHECK
    ADD CONSTRAINT [chk_staging_Department_partition_2]
            CHECK ([DeptID] > N'100' AND [DeptID] <= N'200');

ALTER TABLE [dbo].[Staging_Department_Partition2]
    CHECK CONSTRAINT [chk_staging_Department_partition_2];

/*Load data into staging table*/
INSERT INTO [dbo].[staging_Department] (
    [DeptID],
    [DeptName],
    [ManagerID],
    [ParentDeptID]
)
VALUES (101, 'D101', 1, NULL);

/*Use PARTITION SWITCH IN to efficiently add data to current table */
ALTER TABLE [Staging_Department]
    SWITCH TO [dbo].[Department] PARTITION 2;

如果您嘗試從不含期間定義的資料表執行 PARTITION SWITCH,將會得到錯誤訊息︰

Msg 13577, Level 16, State 1, Line 25 ALTER TABLE SWITCH statement failed on table 'MyDB.dbo.Staging_Department_2015_09_26' because target table has SYSTEM_TIME PERIOD while source table does not have it.

更新資料

您可以利用一般的 UPDATE 陳述式,來更新目前資料表中的資料。 您可以針對「災害」案例,從歷程記錄資料表中更新目前資料表中的資料。 但是,您不能更新 PERIOD 資料行,而且當 SYSTEM_VERSIONING = ON 時,您無法直接更新歷程記錄資料表中的資料。

如果您將 SYSTEM_VERSIONING 設為 OFF 並更新目前和歷程記錄資料表中的資料列,則系統不會保留變更的歷程記錄。

更新目前的資料表

在此範例中,針對 ManagerIDDeptID 的每個資料列更新 10 資料行。 PERIOD 資料行沒有以任何方式被參考。

UPDATE [dbo].[Department]
SET [ManagerID] = 501
WHERE [DeptID] = 10;

但是,您不能更新 PERIOD 資料行,而且您無法更新歷程記錄資料表。 在此範例中,嘗試更新 PERIOD 資料行會產生錯誤。

UPDATE [dbo].[Department]
    SET ValidFrom = '2015-09-23 23:48:31.2990175'
WHERE DeptID = 10;

此陳述式可能會產生以下錯誤。

Msg 13537, Level 16, State 1, Line 3
Cannot update GENERATED ALWAYS columns in table 'TmpDev.dbo.Department'.

從歷程記錄資料表更新目前的資料表

您可以在目前資料表中使用 UPDATE,將實際資料列狀態還原為過去某個特定時間點的有效狀態。 將這視為恢復到「最後已知良好的資料列版本」。 下列範例顯示還原至歷程記錄資料表中截至 2015 年 4 月 25 日且 DeptID10 的值。

UPDATE Department
SET DeptName = History.DeptName
FROM Department FOR SYSTEM_TIME
    AS OF '2015-04-25' AS History
WHERE History.DeptID = 10
    AND Department.DeptID = 10;

刪除資料

您可以利用一般的 DELETE 陳述式,來刪除目前資料表中的資料。 已刪除資料列的結束期間資料行將填入基礎交易的開始時間。 當 SYSTEM_VERSIONINGON 時,您無法從歷程記錄資料表直接刪除資料列。 如果您從目前和歷程記錄資料表設定 SYSTEM_VERSIONING = OFF 和刪除資料列,則系統不會保留變更的歷程記錄。

SYSTEM_VERSIONING = ON 時不支援下列陳述式:

  • TRUNCATE
  • 目前資料表的 SWITCH PARTITION OUT
  • SWITCH PARTITION IN 歷程記錄資料表

用於 MERGE 修改時序表中的資料

MERGE 作業與 INSERTUPDATE 陳述式一樣,受到與 PERIOD 資料行相關的相同限制支援。

CREATE TABLE DepartmentStaging
(
    DeptId INT,
    DeptName VARCHAR (50)
);
GO

INSERT INTO DepartmentStaging
VALUES (1, 'Company Management');

INSERT INTO DepartmentStaging
VALUES (10, 'Science & Research');

INSERT INTO DepartmentStaging
VALUES (15, 'Process Management');

MERGE INTO dbo.Department AS target
USING (
    SELECT DeptId, DeptName
    FROM DepartmentStaging
    ) AS source(DeptId, DeptName)
    ON (target.DeptId = source.DeptId)
WHEN MATCHED
    THEN UPDATE SET DeptName = source.DeptName
WHEN NOT MATCHED
    THEN
        INSERT (DeptId, DeptName)
        VALUES (source.DeptId, source.DeptName);