PostgreSQL Trigger Fonksiyonları Rehberi: INSERT, UPDATE, DELETE Otomasyonu
PostgreSQL'de trigger nasıl yazılır? BEFORE/AFTER farkı, NEW/OLD kayıtları, TG_OP ile işlem tespiti, audit log trigger ve otomatik timestamp güncelleme...
Trigger Nedir?
Trigger, bir tabloda INSERT, UPDATE veya DELETE işlemi gerçekleştiğinde otomatik çalışan bir fonksiyondur. Manuel müdahale gerektirmez — veritabanı seviyesinde otomasyon sağlar.
Yaygın kullanım alanları:
- Audit log tutma (kim, ne zaman, ne değiştirdi?)
updated_attimestamp’ini otomatik güncelleme- Tutarsız veri girişini engelleme
- Bağlı tablolarda cascade güncelleme
Trigger Anatomisi: 2 Parça
PostgreSQL’de trigger fonksiyon ve trigger tanımı olmak üzere 2 parçadan oluşur:
1. CREATE FUNCTION → Ne yapılacak? (mantık)
2. CREATE TRIGGER → Ne zaman, nerede, hangi işlemde? (kural)
Temel Trigger Fonksiyonu
CREATE OR REPLACE FUNCTION my_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
-- Mantığınız buraya
RETURN NEW; -- veya RETURN OLD (DELETE için)
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER my_trigger
AFTER INSERT ON my_table
FOR EACH ROW
EXECUTE FUNCTION my_trigger_function();
Özel Değişkenler: NEW, OLD, TG_OP
Trigger fonksiyonu içinde PostgreSQL otomatik olarak şu değişkenleri sağlar:
| Değişken | Açıklama | INSERT | UPDATE | DELETE |
|---|---|---|---|---|
NEW | Yeni kayıt (eklenen/güncellenen) | ✅ | ✅ | ❌ |
OLD | Eski kayıt (güncellenen/silinen) | ❌ | ✅ | ✅ |
TG_OP | İşlem tipi (text) | 'INSERT' | 'UPDATE' | 'DELETE' |
TG_TABLE_NAME | Tablo adı | ✅ | ✅ | ✅ |
TG_WHEN | 'BEFORE' veya 'AFTER' | ✅ | ✅ | ✅ |
BEFORE vs AFTER — Hangisini Kullanmalı?
| Özellik | BEFORE | AFTER |
|---|---|---|
| Ne zaman çalışır? | İşlemden önce | İşlemden sonra |
NEW değiştirilebilir mi? | ✅ Evet | ❌ Hayır |
| Kullanım alanı | Validasyon, değer değiştirme | Loglama, bildirim |
RETURN değeri | Önemli (NULL → iptal) | Önemsiz |
Pratik Örnek 1: Otomatik updated_at
Her UPDATE’te updated_at alanını otomatik günceller:
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Herhangi bir tabloya ekleyebilirsiniz:
CREATE TRIGGER set_updated_at_trigger
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
Neden BEFORE? Çünkü NEW.updated_at değerini değiştiriyoruz — bu sadece BEFORE’da mümkün.
Pratik Örnek 2: Audit Log Trigger
Tüm değişiklikleri otomatik loglar:
-- Audit tablosu
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
table_name TEXT NOT NULL,
operation TEXT NOT NULL,
old_data JSONB,
new_data JSONB,
changed_by UUID DEFAULT auth.uid(),
changed_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tek fonksiyon, tüm tablolar için
CREATE OR REPLACE FUNCTION audit_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'DELETE' THEN
INSERT INTO audit_log (table_name, operation, old_data)
VALUES (TG_TABLE_NAME, 'DELETE', row_to_json(OLD)::jsonb);
RETURN OLD;
ELSIF TG_OP = 'UPDATE' THEN
INSERT INTO audit_log (table_name, operation, old_data, new_data)
VALUES (TG_TABLE_NAME, 'UPDATE',
row_to_json(OLD)::jsonb, row_to_json(NEW)::jsonb);
RETURN NEW;
ELSIF TG_OP = 'INSERT' THEN
INSERT INTO audit_log (table_name, operation, new_data)
VALUES (TG_TABLE_NAME, 'INSERT', row_to_json(NEW)::jsonb);
RETURN NEW;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- İstediğiniz tablolara ekleyin:
CREATE TRIGGER audit_orders
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW EXECUTE FUNCTION audit_trigger_function();
CREATE TRIGGER audit_products
AFTER INSERT OR UPDATE OR DELETE ON products
FOR EACH ROW EXECUTE FUNCTION audit_trigger_function();
Pratik Örnek 3: Stok Kontrolü (BEFORE INSERT)
Sipariş girilirken stok yeterliliğini kontrol eder:
CREATE OR REPLACE FUNCTION check_stock_before_order()
RETURNS TRIGGER AS $$
DECLARE
available_stock NUMERIC;
BEGIN
SELECT stock_quantity INTO available_stock
FROM products WHERE id = NEW.product_id;
IF available_stock < NEW.quantity THEN
RAISE EXCEPTION 'Yetersiz stok: % adet mevcut, % adet istendi',
available_stock, NEW.quantity;
END IF;
-- Stoku düş
UPDATE products
SET stock_quantity = stock_quantity - NEW.quantity
WHERE id = NEW.product_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_stock_trigger
BEFORE INSERT ON order_items
FOR EACH ROW EXECUTE FUNCTION check_stock_before_order();
Trigger Ne Zaman Kullanılmamalı?
| Durum | Neden? | Alternatif |
|---|---|---|
| Çok karmaşık iş mantığı | Debug zorlaşır | Application layer |
| Dış API çağrısı | Transaction bloklar | Queue + worker |
| Yoğun INSERT tabloları | Performans düşer | Batch processing |
| Döngüsel bağımlılık | Sonsuz döngü riski | Dikkatli tasarım |
Supabase’de Trigger Kullanımı
Supabase Dashboard → SQL Editor’den doğrudan çalıştırabilirsiniz:
-- Supabase'de auth.uid() ile kullanıcı takibi
CREATE OR REPLACE FUNCTION set_user_id()
RETURNS TRIGGER AS $$
BEGIN
NEW.user_id = auth.uid();
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER auto_set_user
BEFORE INSERT ON user_notes
FOR EACH ROW EXECUTE FUNCTION set_user_id();
Dikkat Edilecekler
- RETURN değeri: BEFORE trigger’da
RETURN NULLyaparsanız işlem iptal olur. - Performans: Her satır için çalışır (
FOR EACH ROW). Bulk insert’lerde yavaşlatabilir. - SECURITY DEFINER: Trigger fonksiyonu RLS bypass edebilir — dikkatli kullanın.
- Debugging:
RAISE NOTICE 'debug: %', NEW.column_name;ile debug yapabilirsiniz.
İlgili Yazılar
- PostgreSQL Merkezi Audit Log — Production audit sistemi
- SECURITY DEFINER vs INVOKER — Fonksiyon güvenliği
- Supabase RLS — Trigger + RLS etkileşimi
- pg_cron ile Zamanlanmış Görevler — Trigger’a alternatif
Bu rehber PostgreSQL Trigger Docs ve Supabase Database Functions dokümantasyonuna dayanarak hazırlanmıştır.