This chapter explains how to implement historical queries in SQL databases, allowing you to retrieve past states of data over time. Historical queries are essential for tracking changes, auditing data, and performing time-based analyses. We’ll cover SQL methods to achieve this, from versioned tables and temporal tables to implementing custom tracking mechanisms.
Historical queries allow you to view data as it existed at a specific point in time. They are commonly used in:
SQL offers several ways to implement historical data tracking, from built-in temporal tables to manually managed versioning techniques.
Temporal tables are a powerful feature in modern SQL databases (e.g., SQL Server, PostgreSQL) that automatically track changes to data. These tables store two versions: a “current” version and a “history” version that captures old records.
CREATE TABLE Employee (
EmployeeID INT PRIMARY KEY,
Name NVARCHAR(100),
Position NVARCHAR(50),
Salary DECIMAL(10, 2),
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
) WITH (SYSTEM_VERSIONING = ON);
ValidFrom
and ValidTo
store the period each record is valid.SYSTEM_VERSIONING = ON
enables version tracking, creating a hidden history table that stores previous versions of each row.To retrieve past records, specify the time range:
SELECT *
FROM Employee
FOR SYSTEM_TIME AS OF '2024-01-01';
FOR SYSTEM_TIME AS OF
lets you view data as it existed on a specific date.If your database doesn’t support temporal tables, you can create a custom history table that tracks changes by inserting a new record whenever a row is updated.
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
CustomerID INT,
OrderDate DATE,
Amount DECIMAL(10, 2),
IsActive BIT
);
CREATE TABLE OrderHistory (
OrderID INT,
CustomerID INT,
OrderDate DATE,
Amount DECIMAL(10, 2),
ModifiedDate DATETIME DEFAULT GETDATE(),
ChangeType NVARCHAR(50)
);
CREATE TRIGGER trg_OrderHistory
ON Orders
AFTER UPDATE, DELETE
AS
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN
INSERT INTO OrderHistory (OrderID, CustomerID, OrderDate, Amount, ModifiedDate, ChangeType)
SELECT OrderID, CustomerID, OrderDate, Amount, GETDATE(), 'Deleted'
FROM DELETED;
END
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
INSERT INTO OrderHistory (OrderID, CustomerID, OrderDate, Amount, ModifiedDate, ChangeType)
SELECT OrderID, CustomerID, OrderDate, Amount, GETDATE(), 'Updated'
FROM INSERTED;
END
END;
trg_OrderHistory
captures changes in the Orders
table.DELETED
and INSERTED
(SQL’s pseudo-tables for modified records) are inserted into OrderHistory
, along with the change type (Updated
or Deleted
).Retrieve changes made to a specific order:
SELECT *
FROM OrderHistory
WHERE OrderID = 101;
Slowly Changing Dimensions (SCD) track changes in data dimensions over time, commonly used in data warehousing.
CREATE TABLE Product (
ProductID INT,
Name NVARCHAR(50),
Price DECIMAL(10, 2),
StartDate DATE,
EndDate DATE,
IsCurrent BIT,
PRIMARY KEY (ProductID, StartDate)
);
BEGIN TRANSACTION;
-- Close the current record
UPDATE Product
SET EndDate = GETDATE(), IsCurrent = 0
WHERE ProductID = 1 AND IsCurrent = 1;
-- Insert the new record
INSERT INTO Product (ProductID, Name, Price, StartDate, EndDate, IsCurrent)
VALUES (1, 'New Product Name', 99.99, GETDATE(), NULL, 1);
COMMIT TRANSACTION;
EndDate
and IsCurrent = 0
.Time-based partitioning organizes data by date, allowing efficient access to historical data.
CREATE TABLE Sales_2023 (
SaleID INT PRIMARY KEY,
SaleAmount DECIMAL(10, 2),
SaleDate DATE
);
CREATE TABLE Sales_2024 (
SaleID INT PRIMARY KEY,
SaleAmount DECIMAL(10, 2),
SaleDate DATE
);
Sales_2023
, Sales_2024
) allow easy access to historical data.Implementing historical queries in SQL enables you to track and analyze changes over time, making it essential for auditing, reporting, and compliance. Using temporal tables, custom history tables, and partitioning strategies allows for efficient and flexible historical data management, supporting a wide range of business needs and ensuring your data remains accessible and secure. Happy coding !❤️