Temporal Tables (Sistem Versiyonlu Tablolar), SQL Server 2016 ve sonraki sürümlerde sunulan, verilerin zaman içindeki değişimlerini otomatik olarak takip eden bir özelliğidir. Bu tablolar, veri değişikliklerinin tarihçesini saklayarak “zamanda yolculuk” yapabilme imkanı sağlar. Bir raporlama aracı olarak kullanılabilir. Herhangi bir veri kaybı için bir önlem mekanizması olarak da kullanılır.
Temporal Tables yapısında Mevcut verilerin tutulduğu Ana tablo ve Normal bir tablo gibi çalışır ancak zaman bilgisi içerir. Bir diğer tablo türümüz ise History Table ana tablodaki verilerin geçmiş durumlarını saklar. Sistem tarafından otomatik olarak yönetilir.
Temporal Tables yapılarında önemli olan zaman kavramları mevcuttur. Bu zaman kavramları DATETIME2 türündendir. Bunlar aşağıdaki gibi iki zaman kavramıdır.
- SysStartTime: Kaydın geçerli olduğu başlangıç zamanı
- SysEndTime: Kaydın geçerli olduğu bitiş zamanı
Temporal olarak oluşturulacak tabloda bir primary key olmalıdır. Hangi verilerin değişime uğrayacağı bu primary key aracılığıyla ayırt etmiş olacağız. Geçmiş tablosu doğrudan değiştirilemez (INSERT, UPDATE, DELETE) TRUNCATE TABLE komutu kullanılamaz.
Yeni Tablo Oluşturma
CREATE TABLE Product
(
ProductID INT PRIMARY KEY,
ProductName NVARCHAR(100) NOT NULL,
CategoryID INT,
Price DECIMAL(10,2) NOT NULL,
StockQuantity INT NOT NULL,
Discontinued BIT DEFAULT 0,
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ProductHistory));
Varolan Tabloyu Temporal Table’a Dönüştürme
Tablomuzda veri yoksa aşağıdaki şekilde yapılmaktadır. İlk komut çalıştırıldıktan sonra ikinci komut çalıştırılır.
--Eğer kolonlarımızın içerisinde veri yoksa
ALTER TABLE Product
ADD
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime);
--Sistem versiyonlamayı aktif edelim
ALTER TABLE Product
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ProductHistory));
Eğer tablomuzda veri varsa aşağıdaki yapıda oluşturulmaktadır. İlk komut çalıştırıldıktan sonra ikinci komut çalıştırılır.
ALTER TABLE Product
ADD
StartDate DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL
DEFAULT CAST('1900-01-01 00:00:00.0000000' AS DATETIME2),
EndDate DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL
DEFAULT CAST('9999-12-31 23:59:59.9999999' AS DATETIME2),
PERIOD FOR SYSTEM_TIME (StartDate, EndDate);
--Sistem versiyonlamayı aktif edelim
ALTER TABLE Product
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.ProductHistory));
Yukarıdaki tablomuzu oluşturduktan sonra History tablomuzun mevcut tablomuzun altında oluştuğunu görebiliriz.

--Ürün ekleme
INSERT INTO Product (ProductID, ProductName, CategoryID, Price, StockQuantity)
VALUES (1, 'Wireless Mouse', 5, 29.99, 100);
--İki güncelleme yapılır.
UPDATE Product SET Price = 24.99 WHERE ProductID = 1;
UPDATE Product SET StockQuantity = 85 WHERE ProductID = 1;
Yukarıdaki update işlemi yapıldığında history tablosunda SysEndTime değeri verinin güncellendiği anlık getdate() değeri ile set edilmektedir. SysStartTime parametresi ise insert veya update ifadesinin tablomuza ilk yapıldığı hali olarak görülmektedir. Test işlemini sıralı yaparak bu kavramı daha iyi anlayabiliriz. Aşağıdaki resimde dikkat edilirse 2. update sonrasında değer history tablosuna kaydedildiği zaman history tablosunda bulunan ilk değerin SysEndTime değeri 2. update edilen değerin history tablosunda SysStartTime değeri olmuş olacaktır. Bu güncelleme değerleri ilgili kolon üzerinde birbirini takip etmektedir.

Ürünü tamamen silelim
DELETE FROM Product WHERE ProductID = 1
History tablosunda silinen değerin geldiğini görmüş oluyoruz.

Yukarıdaki oluşturulan tablomuzu sorgulama komutları aşağıdaki gibidir.
1. Belirli Bir Zamandaki Veriler (AS OF)
-- 15 Haziran 2023 saat 10:00'daki veriler
SELECT * FROM Product
FOR SYSTEM_TIME AS OF '2023-06-15 10:00:00'
WHERE ProductID = 1;
2. İki Tarih Arasındaki Tüm Değişiklikler (FROM )
SELECT * FROM Product
FOR SYSTEM_TIME FROM '2023-06-15 10:00:00' TO '2023-07-15 10:00:00'
WHERE ProductID = 1;
3. Between komutu ilede aynı işlemi yapabiliriz.
-- 1 Ocak 2023 ile 1 Temmuz 2023 arasındaki tüm versiyonlar
SELECT * FROM Product
FOR SYSTEM_TIME BETWEEN '2023-01-01' AND '2023-07-01'
WHERE CategoryID = 5;
4. Belirli Aralıkta Başlayan ve Biten Kayıtlar (CONTAINED IN)
-- Sadece 2023'ün 1. çeyreğinde aktif olan kayıtlar
SELECT * FROM Product
FOR SYSTEM_TIME CONTAINED IN ('2023-01-01', '2023-03-31')
Temporal Table’ı Pasif Hale Getirme:
-- Sistem versiyonlamayı kapatma
ALTER TABLE Product SET (SYSTEM_VERSIONING = OFF);
Bu yapı ile log tablosu normal bir tablo yapısına gelmektedir.
Temporal özelliğini kalıcı olarak kaldırmak için:
1. Adım: Sistem Versiyonlamayı Kapat
ALTER TABLE Product SET (SYSTEM_VERSIONING = OFF);
2. Adım: PERIOD Tanımını Kaldır
ALTER TABLE Product DROP PERIOD FOR SYSTEM_TIME;
3. Adım: Zaman Sütunlarını Sil
ALTER TABLE Product DROP COLUMN SysStartTime, SysEndTime;
4. Adım: Geçmiş Tabloyu Sil
DROP TABLE ProductHistory;
Temporal Tables, veri değişikliklerinin izlenmesi gereken uygulamalarda oldukça kullanışlıdır. Özellikle finansal sistemler, insan kaynakları uygulamaları ve veri denetimi gerektiren projelerde sıklıkla kullanılır.
Başka makalede görüşmek dileğiyle..
Ey iman edenler, sabredin ve sabırda yarışın, (sınırlarda) nöbetleşin. Allah’tan korkun. Umulur ki kurtulursunuz. Al-i İmran Suresi, 200. ayet