Introduction
Tracking changes to data is a common requirement in modern applications. Organizations often need to know what changed, when it changed, and what the previous values were. Whether it's for auditing, compliance, reporting, or recovering accidentally modified data, maintaining historical records is essential.
SQL Server Temporal Tables provide a built-in mechanism for automatically storing and managing the history of data changes. Instead of creating custom audit tables or writing complex triggers, SQL Server records every update and delete operation while preserving previous versions of rows.
In this article, you'll learn what Temporal Tables are, how they work, how to create and query them, and the best practices for using them effectively.
What Are Temporal Tables?
A Temporal Table, also known as a system-versioned temporal table, automatically keeps a complete history of data changes.
Each temporal table consists of:
A current table that stores the latest data.
A history table that stores previous versions of rows.
Two system-managed datetime columns that define the validity period of each record.
Whenever a row is updated or deleted, SQL Server moves the previous version to the history table automatically.
This eliminates the need for custom auditing logic in many scenarios.
Why Use Temporal Tables?
Maintaining historical data manually often requires triggers, audit tables, or application-level code.
Temporal Tables simplify this process by providing:
Automatic history tracking
Built-in auditing
Point-in-time data recovery
Change history analysis
Simplified reporting
Reduced development effort
Native SQL Server support
These features make Temporal Tables an excellent choice for applications that require historical data.
How Temporal Tables Work
When a record is inserted, it is stored in the main table.
When the record is updated:
The existing row is copied to the history table.
The current table is updated with the new values.
SQL Server updates the validity period automatically.
When a record is deleted:
The deleted row is moved to the history table.
The row is removed from the current table.
All of this happens without requiring additional application code.
Create a Temporal Table
The following example creates a temporal table for storing employee information.
CREATE TABLE Employees
(
EmployeeId INT PRIMARY KEY,
Name NVARCHAR(100),
Department NVARCHAR(100),
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH
(
SYSTEM_VERSIONING = ON
);
SQL Server automatically creates and manages the associated history table.
Insert Data
Insert data just as you would with any regular table.
INSERT INTO Employees
(EmployeeId, Name, Department)
VALUES
(1, 'John Smith', 'Sales');
At this point, the current table contains one record, while the history table remains empty because no changes have occurred yet.
Update Data
Now update the employee's department.
UPDATE Employees
SET Department = 'Marketing'
WHERE EmployeeId = 1;
SQL Server automatically:
Stores the previous version in the history table.
Updates the current table.
Adjusts the validity period.
No trigger or manual insert into an audit table is required.
View Current Records
Query the current table as usual.
SELECT *
FROM Employees;
This returns only the latest version of each record.
View Historical Data
To retrieve all historical versions of a record, use the FOR SYSTEM_TIME ALL clause.
SELECT *
FROM Employees
FOR SYSTEM_TIME ALL;
The result includes:
Current records
Previous versions
Validity periods
This provides a complete history of changes.
Query Data at a Specific Point in Time
One of the most powerful features of Temporal Tables is point-in-time querying.
For example:
SELECT *
FROM Employees
FOR SYSTEM_TIME AS OF '2026-07-20 10:00:00';
This query returns the data exactly as it existed at the specified date and time.
Join the conversation! Your thoughts help the community grow.