What is a temporal table?
Temporal tables give us the possibility to retrieve data from any point in the past and for every data change (Update, Delete, Merge). With temporal table users can recover data from accidental changes (update/delete) as well as audit all changes to data, etc. Temporary table is a new feature in SQL Server available from SQL Server 2016 CTP2 version. A Temporal table is composed of two parts (tables), the first part is the table on which is enabled data tracking and it’s called a System-Versioned table, this table contains current (actual) data, the second part is the table in which is stored any data changes that were made (Update, Delete, Merge) in a System-Versioned table and it’s called History table.What every temporal table must have?
datetime2 columns Every temporal table must have two columns with a datetime2 data type. These columns are used exclusively by the system to record the period of validity for each row whenever a row is changed. Both columns should be defined as NOT NULL. If there are no NOT NULL constraints for datetime2 columns, the system will automatically set them as NOT NULL. If NULL constraints are applied to these columns, then the system will raise an error:Msg 13587, Level 16, State 1, Line 1 Period column ‘StartTime’ in a system-versioned temporal table cannot be nullable.
One datetime2 column must have the GENERATED ALWAYS AS ROW START option set and the second datetime2 column must have the GENERATED ALWAYS AS ROW END option set. The GENERATED ALWAYS AS ROW START column represents the time when the row data became current, basically on an INSERT/UPDATE of the record in the system-versioned temporal table, the system will set current UTC time based on the system clock where the SQL Server instance runs. The GENERATED ALWAYS AS ROW END column represents the time when the row data was no longer current. This column indicates the time when the changes UPDATE/DELETE occur. The system will set the current UTC time. Primary key Also a system-versioned temporal table must have a primary key defined. If the table doesn’t have a defined the primary key, the following error will appear:Msg 13553, Level 16, State 1, Line 1 System versioned temporal table ‘test.dbo.people’ must have primary key defined.
Attributes The table must have a PERIOD FOR SYSTEM_TIME (<startcol>,<endcol>) clause with two datetime2 columns in it. PERIOD FOR SYSTEM_TIME specifies the name of the columns that the system will use to record the period for which a record is valid:StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) )
StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON);
StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));
MSSQL_TemporalHistoryFor_693577509
Where the number 693577509 is object_id for the system-versioned table. Here an example of a system-versioned table:CREATE TABLE People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));
Creating a System-Versioned temporal table
Depending on the scenario, a system-versioned temporal table can be created by modifying an existing table from the database by adding temporal attributes or creating new system-versioned temporal table. There are three ways to create a system-versioned temporal table: Temporal table with an anonymous history table, creating a temporal table with a default history table or creating a temporal table with a user-defined history table. Temporal table with an anonymous history table Basically, when creating this type of temporal table, the only option that is omitted from the code that is shown above is a HISTORY_TABLE parameter:CREATE TABLE People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON);
MSSQL_TemporalHistoryFor_613577224
Creating a temporal table with a default history table This approach allows the user to pick a much friendlier/meaningful name for history table in the HISTORY_TABLE parameter, rather than to let system to pick a name.CREATE TABLE People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));
Msg 13539, Level 15, State 1, Line 54 Setting SYSTEM_VERSIONING to ON failed because history table ‘PeopleHistory’ is not specified in two-part name format.
Creating a temporal table with a user-defined history table Creating user-defined history table is useful when in the history table needs additional options such as an index in order to obtain a better query performance. The history table cannot have a primary/foreign key, triggers, table constraints, unique index. Otherwise, the following error will be displayed:Msg 13515, Level 16, State 1, Line 45 Setting SYSTEM_VERSIONING to ON failed because history table ‘test.dbo.PeopleHistory’ has custom unique keys defined. Consider dropping all unique keys and trying again.
The History and System-Versioned table must have the same number of the columns, the same column names and the same data types in order to a temporal table be created correctly. The below example demonstrates the effect of creating a history table with a different column name (NickName2) than the column name (NickName) in the versioned table. Copy the following code in the query editor and execute:CREATE TABLE PeopleHistory( PeopleID int NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName2 varchar(25), StartTime datetime2 NOT NULL, EndTime2 datetime2 NOT NULL )
CREATE TABLE dbo.People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));Msg 13524, Level 16, State 1, Line 45 Setting SYSTEM_VERSIONING to ON failed because column ‘NickName2’ at ordinal 4 in history table ‘test.dbo.PeopleHistory’ has a different name than the column ‘NickName’ at the same ordinal in table ‘test.dbo.People’.
The code below will successfully create system versioned and user-defined history table:CREATE TABLE PeopleHistory( PeopleID int NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 NOT NULL, EndTime2 datetime2 NOT NULL )
CREATE TABLE dbo.People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25), StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime,EndTime) ) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));CREATE TABLE People( PeopleID int PRIMARY KEY NOT NULL, Name varchar(50) Null, LastName varchar(100) NULL, NickName varchar(25) )
INSERT INTO dbo.People ( PeopleID, Name, LastName, NickName ) VALUES ( 1, — PeopleID – int ‘Marko’, — Name – varchar ‘Zivkovic’, — LastName – varchar ‘Ziva’ — NickName – varchar )ALTER TABLE dbo.People SET (SYSTEM_VERSIONING = ON)
Msg 13510, Level 16, State 1, Line 1 Cannot set SYSTEM_VERSIONING to ON when SYSTEM_TIME period is not defined.
As mentioned earlier, each temporal table must have two columns with datetime2 data type, otherwise the error above will be displayed. Now lets try to execute the below statement with two datetime2 columns:ALTER TABLE dbo.People ADD StartTime DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL, EndTime DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL, PERIOD FOR SYSTEM_TIME (StartTime, EndTime)
Msg 4901, Level 16, State 1, Line 4 ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column ‘StartTime’ cannot be added to non-empty table ‘People’ because it does not satisfy these conditions.
This error occurs, because the system will not allow to add NOT NULL columns in the table which already have data in it. To correct this, let’s add a default value for the datetime2 columns and enable system versioning with default name for the history table:ALTER TABLE dbo.People ADD StartTime DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN DEFAULT GETUTCDATE(), EndTime DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN DEFAULT CONVERT(DATETIME2, ‘9999-12-31 23:59:59.9999999’), PERIOD FOR SYSTEM_TIME (StartTime, EndTime) Go ALTER TABLE dbo.People SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE=dbo.PeopleHistory)) GO
SELECT * FROM dbo.People
SELECT Name, LastName, NickName, StartTime, EndTime FROM dbo.People
INSERT INTO dbo.People VALUES (2, ‘Alan’, ‘Beker’, ‘Al’)
- Insert data when the PERIOD columns are omitted from the INSERT statement column list:
INSERT dbo.People (PeopleID, Name, LastName, NickName) VALUES (2, ‘Alan’, ‘Beker’, ‘Al’)
- Insert data when the PERIOD columns are in the INSERT statement column list:
INSERT dbo.People (PeopleID, Name, LastName, NickName, StartTime, EndTime) VALUES (2, ‘Alan’, ‘Beker’, ‘Al’, DEFAULT, DEFAULT)
- Insert data when the INSERT column list is not specified
INSERT dbo.People VALUES (3, ‘Joe’, ‘Anderson’, ‘Jo’, DEFAULT, DEFAULT)
INSERT dbo.People VALUES (4, ‘Mike’, ‘Carter’, ‘Mik’)
Msg 213, Level 16, State 1, Line 16 Column name or number of supplied values does not match table definition.
When inserting data into a temporal table the system versioned (current) table will be affected, the history table will be empty: System versioned table:SELECT p.* FROM dbo.People p
SELECT ph.* FROM dbo.PeopleHistory ph
UPDATE dbo.People SET dbo.People.NickName = ‘Mare’ WHERE dbo.People.PeopleID = 1
–Get the records from the temporal table SELECT p.* FROM dbo.People p –Get the records from the history table SELECT ph.* FROM dbo.PeopleHistory ph
UPDATE dbo.PeopleHistory SET dbo.PeopleHistory.NickName = ‘Maruska’ WHERE dbo.PeopleHistory.PeopleID = 1
Msg 13561, Level 16, State 1, Line 54 Cannot update rows in a temporal history table ‘test.dbo.PeopleHistory’.
The only way to update a history (PeopleHistory) table is to set SYSTEM_VERSIONING to OFF in the system versioned (People) table:ALTER TABLE dbo.People SET (SYSTEM_VERSIONING = OFF)
UPDATE dbo.People SET StartTime=GETUTCDATE() WHERE dbo.People.PeopleID = 2
Msg 13537, Level 16, State 1, Line 54 Cannot update GENERATED ALWAYS columns in table ‘test.dbo.People’.
In order to be available to update PERIOD columns the following statement must be executed:ALTER TABLE dbo.People DROP PERIOD FOR SYSTEM_TIME GO
UPDATE dbo.People SET StartTime=GETUTCDATE() WHERE dbo.People.PeopleID = 2
(1 row(s) affected)
Deleting data Let’s delete the record from the People table where the PeopleID is 1DELETE FROM dbo.People WHERE PeopleID = 1
–Get the records from the temporal table SELECT p.* FROM dbo.People p –Get the records from the history table SELECT ph.* FROM dbo.PeopleHistory ph
DELETE FROM dbo.PeopleHistory WHERE PeopleID = 1
Msg 13560, Level 16, State 1, Line 61 Cannot delete rows from a temporal history table ‘test.dbo.PeopleHistory’.
This is happening because the update/delete operations are not allowed on the history table as long as SYSTEM_VERSIONING is enabled. To delete history and system versioned table, execute the code below:–Disable the system versioning ALTER TABLE dbo.People SET (SYSTEM_VERSIONING = OFF) GO –Drop Period definition ALTER TABLE dbo.People DROP PERIOD FOR SYSTEM_TIME GO –Now drop People and PeopleHistory tables DROP TABLE dbo.People DROP TABLE dbo.PeopleHistory
- How to connect to a remote MySQL server using SSL on Ubuntu - April 28, 2020
- How to install MySQL on Ubuntu - March 10, 2020
- Using SSH keys to connect to a remote MySQL Server - November 28, 2019