Recently someone has been changing data in a table on a legacy application written more than a decade ago. While the DEV team works on a solution to log user access for this, more importantly I need to easily get the original data back into the table, quickly. I can accomplish this by converting the table to a SYSTEM-VERSIONED TEMPORAL TABLE. A TEMPORAL TABLE attaches a history table to the original one, offering just the solution I quickly need.
In this post I will share my code to:
- Create a NEW temporal table.
- CONVERT an EXISTING table to temporal.
I already know there are no triggers on my table and it does not participate in a cascade delete, so I’m expecting NOT to run into any performance or data rollback issues.
Once I have completed my task, I will have my original table of data rows aligned in columns with its keys, constraints, indexes, and statistics. AND– a new history table with copies of data (upon change) and its own copy of constraints, indexes and statistics.
CREATE A NEW TEMPORAL TABLE
If this table did not already exist, I could create it newly, using this code:
CREATE TABLE [dbo].[MyTable](
[ID] [INT] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
-- ALL OTHER COLUMNS GO HERE
[Column1] [VARCHAR](50) NULL,
[Column2] [VARCHAR](50) NULL,
-- REQUIRED CODE
[SysTimeStart] datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
[SysTimeEnd] datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysTimeStart,SysTimeEnd)) ON [PRIMARY]
WITH(SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.MyTable_History)) ; --<<< CHANGE TABLENAME
Optionally, I may want to find out the Primary Key (PK) name that was auto-generated and change that.
-- EXAMPLE to change PK name
EXEC sp_rename 'MyTable.PK__MyTable__9999999999999', 'PK_MyTable_ID';
CONVERT AN EXISTING TABLE TO TEMPORAL
Since my table already exists, I just need to add the history table to it and wire it up.
-- NOTE I RUN EACH LINE COMMAND INDIVIDUALLY.
ALTER TABLE dbo.MyTable ADD [SysTimeStart] datetime2;
ALTER TABLE dbo.MyTable ADD [SysTimeEnd] datetime2;
UPDATE dbo.MyTable SET [SysTimeStart] = '19000101 00:00:00.0000000', [SysTimeEnd] = '99991231 23:59:59.9999999';
ALTER TABLE dbo.MyTable ALTER COLUMN [SysTimeStart] datetime2 NOT NULL;
ALTER TABLE dbo.MyTable ALTER COLUMN [SysTimeEnd] datetime2 NOT NULL;
ALTER TABLE dbo.MyTable ADD PERIOD FOR SYSTEM_TIME (SysTimeStart, SysTimeEnd);
ALTER TABLE dbo.MyTable SET(SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.MyTable_History, DATA_CONSISTENCY_CHECK = ON));
I want to verify that my table is working so I’m going to insert a couple rows and then change one.
INSERT INTO dbo.MyTable (Column1, Column2)
VALUES ('AAA111','AAA222'),('BBB111','BBB222');
SELECT * FROM dbo.MyTable
SELECT * FROM dbo.MyTable_History ORDER BY SysTimeEnd DESC;
Now to make an update to change something.
UPDATE dbo.MyTable SET Column1 = 'Testing' WHERE ID = 2
SELECT * FROM dbo.MyTable
SELECT * FROM dbo.MyTable_History ORDER BY SysTimeEnd DESC;
DROP TEMPORAL TABLE ERROR
Oooops! The regular DROP TABLE command does not work with temporal tables. What do I do now?
DROP TABLE dbo.MyTable;
I must separate my history table before I can drop the table. I like this option, because if for some reason I want to rebuild my main table and not lose any of the historical data, I can easily do that.
-- This separates the tables so they can be dropped or modified.
ALTER TABLE dbo.MyTable SET (SYSTEM_VERSIONING = OFF);
And I can reconnect the HISTORY table later, using this command:
ALTER TABLE dbo.MyTable SET (SYSTEM_VERSIONING = ON
(HISTORY_TABLE=dbo.MyTable_History,DATA_CONSISTENCY_CHECK=[ON/OFF])
);
When I want to know more about temporal tables, I refer to this white paper at Microsoft: