31.01.2026

Bitemporal Data Nedir? “Ne Zaman Oldu” ve “Ne Zaman Biliyorduk” Sorularını Aynı Anda Cevapla

Bitemporal model ile geçmişe dönük düzeltmeleri kaybetmeden, hem olay zamanı hem kayıt zamanı üzerinden güvenilir raporlama yapın.

Bazı hatalar “yanlış veri” değildir; sadece geç öğrenilmiş doğrudur. Finans, sigorta, envanter veya abonelik gibi alanlarda şu iki soru sürekli karşımıza çıkar:

  • Gerçekte ne zaman oldu? (event/effective time)
  • Biz bunu ne zaman sisteme kaydettik? (system/recorded time)

Bu iki zaman eksenini birlikte tutan yaklaşıma bitemporal data denir. Tek bir “updated_at” alanı, geçmişe dönük düzeltmelerde hem denetimi hem de doğru raporlamayı bozar.

Problem: “Geriye Dönük Düzeltme” Raporları Neden Bozar?

Örnek: Bir müşterinin abonelik planı 1 Ocak’ta Pro olmuş olsun. Ancak bu değişiklik sistemde 10 Ocak’ta fark edilip girilmiş olsun.

  • 5 Ocak’ta “hangi planlar aktifti?” raporunu 6 Ocak’ta çekseydiniz müşteri Basic görünecekti.
  • Aynı raporu 12 Ocak’ta çektiğinizde müşteri Pro görünecek.

İki raporun farklı çıkması bazen beklenen şeydir: “O gün bildiğimiz gerçek” ile “bugün bildiğimiz gerçek” farklıdır.

Bitemporal model, ikisini de sorgulanabilir kılar.

Bitemporal Modelin Temel Fikri

Her kayıt için iki aralık tutarsınız:

  1. Valid Time (Geçerlilik Zamanı): Gerçek dünyada geçerli olduğu aralık
  2. System Time (Sistem Zamanı): Veritabanında hangi aralıkta “doğru kabul edilip saklandığı”

Pratikte genelde şu alanlarla temsil edilir:

  • valid_from, valid_to
  • system_from, system_to

*_to alanı çoğu zaman “sonsuz” anlamına gelen bir değerle (örn. 9999-12-31) veya NULL ile tutulur.

Küçük Bir Örnek: Abonelik Planı

Tablo: subscription_plan_history

-- Örnek şema (basit)
CREATE TABLE subscription_plan_history (
  customer_id   BIGINT NOT NULL,
  plan          TEXT   NOT NULL,
  valid_from    DATE   NOT NULL,
  valid_to      DATE   NOT NULL,
  system_from   TIMESTAMP NOT NULL,
  system_to     TIMESTAMP NOT NULL,
  PRIMARY KEY (customer_id, valid_from, system_from)
);

Senaryo

  • Müşteri 1 Ocak itibarıyla Pro’ya geçmiş.
  • Biz bu bilgiyi 10 Ocak’ta öğrenip girdik.

İlk giriş (10 Ocak’ta):

INSERT INTO subscription_plan_history
(customer_id, plan, valid_from, valid_to, system_from, system_to)
VALUES
(42, 'PRO', DATE '2026-01-01', DATE '9999-12-31', TIMESTAMP '2026-01-10 09:00:00', TIMESTAMP '9999-12-31 00:00:00');

Sorgu 1: “Gerçekte 5 Ocak’ta hangi plandaydı?”

Bu, valid time sorusu:

SELECT plan
FROM subscription_plan_history
WHERE customer_id = 42
  AND DATE '2026-01-05' >= valid_from
  AND DATE '2026-01-05' <  valid_to
  AND TIMESTAMP '2026-01-31 00:00:00' >= system_from
  AND TIMESTAMP '2026-01-31 00:00:00' <  system_to;

Burada ikinci zaman filtresi “hangi bilgi setiyle bakıyoruz?” sorusunu cevaplar: 31 Ocak’ta bildiğimiz veriye göre.

Sorgu 2: “6 Ocak’ta rapor alsaydım ne görecektim?”

Bu sefer system time’ı 6 Ocak’a çekersiniz:

SELECT plan
FROM subscription_plan_history
WHERE customer_id = 42
  AND DATE '2026-01-05' >= valid_from
  AND DATE '2026-01-05' <  valid_to
  AND TIMESTAMP '2026-01-06 12:00:00' >= system_from
  AND TIMESTAMP '2026-01-06 12:00:00' <  system_to;

10 Ocak’ta girildiği için 6 Ocak “bilgi anında” bu kayıt görünmez. İşte denetim ve raporlama netliği burada gelir.

Düzeltme Nasıl Yapılır? (Kayıt Silmeden)

Bitemporal yaklaşımda “update” çoğu zaman eski kaydı kapat, yenisini aç şeklinde yapılır.

Örn. 15 Ocak’ta öğreniyorsunuz ki Pro geçişi aslında 3 Ocak’ta başlamış.

  • Mevcut kaydın system_to’sunu 15 Ocak yaparsınız (artık sistem açısından “geçersiz”).
  • Yeni doğru kaydı 15 Ocak sistem zamanı ile eklersiniz.

Bu sayede:

  • “Bugün bildiğimiz doğru” değişir.
  • “O gün ne biliyorduk?” sorusu bozulmaz.

Ne Zaman Değer? Ne Zaman Fazla?

Değerli olduğu yerler:

  • Finansal raporlama ve denetim (audit)
  • Faturalama/abonelik geçmişi
  • Envanter ve fiyat geçerlilikleri
  • Hukuki/regülasyon gerektiren alanlar

Fazla gelebileceği yerler:

  • Basit CRUD uygulamaları
  • “Son değer yeter” denilen dashboard’lar

Uygulamada 3 İpucu

  1. Zaman aralıklarını çakıştırmayın: Aynı customer_id için valid aralıkların mantıksal olarak tutarlı olduğundan emin olun.
  2. ‘Sonsuz’ değer standardı belirleyin: NULL mı, 9999-12-31 mi? Her yerde aynı olsun.
  3. Sorgu katmanı şart: Bitemporal tabloları ham haliyle her yere açmak yerine, sık kullanılan “as of” sorgularını view veya repository fonksiyonlarıyla standardize edin.

Bitemporal data, “geçmişi düzeltirken geçmişi silmeme” disiplinidir. Özellikle raporların tutarlılığı ve denetim izi önemliyse, updated_at yerine iki zaman ekseniyle düşünmek sisteminize ciddi bir olgunluk katar.