📖 Šta su Trigeri (Okidači)?
Triger je posebna vrsta stored procedure koja se izvršava automatski kao odgovor na određeni događaj (event). To može biti promjena podataka (DML), promjena strukture (DDL) ili prijava korisnika na server. Trigeri su "nevidljiva ruka" baze koja garantuje da se određena pravila izvrše bez obzira na to koji dio aplikacije šalje SQL kod.
✨ Magic Tables: Inserted i Deleted
Kada se triger pokrene, SQL Server kreira dvije privremene, memorijske tabele koje postoje samo unutar scope-a trigera:
- INSERTED: Sadrži nove redove (kod INSERT-a) ili nove verzije redova (kod UPDATE-a).
- DELETED: Sadrži obrisane redove (kod DELETE-a) ili stare verzije redova (kod UPDATE-a).
🚫 Najveća zabluda o trigerima
Mnogi vjeruju da se triger pokreće za svaki red posebno. OVO JE NETAČNO.
Triger se pokreće jednom po SQL naredbi (npr. ako uradite update 1000 redova, triger leti JEDNOM,
a tabela inserted će imati 1000 redova). Kod trigera MORATE pisati set-based kod.
⚡ DML Trigeri: AFTER vs INSTEAD OF
1. AFTER Trigeri
Izvršavaju se nakon što je SQL operacija (i sve constraint provjere) uspješno završena. Idealni za Auditing (zapisivanje ko je šta promijenio).
2. INSTEAD OF Trigeri
Presreću operaciju i izvršavaju umjesto nje. Najčešće se koriste na Complex Views kako bi omogućili unos podataka u tabele koje su spojene u pogledu.
CREATE TRIGGER trg_AuditBudgetChanges
ON Stats.Projects
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Bilježimo promjenu samo ako je kolona 'Budget' stvarno promijenjena
IF UPDATE(Budget)
BEGIN
INSERT INTO Audit.BudgetLog (ProjectID, OldBudget, NewBudget, ChangedDate, ChangedBy)
SELECT i.ProjectID, d.Budget, i.Budget, GETDATE(), SYSTEM_USER
FROM inserted i
JOIN deleted d ON i.ProjectID = d.ProjectID
WHERE i.Budget <> d.Budget; -- Ignorišemo "fake" updejte
END
END;
GO
🛡️ DDL Trigeri: Zaštita strukture
Želite spriječiti da bilo ko obriše (DROP) tabelu u produkciji? DDL trigeri su rješenje.
CREATE TRIGGER trg_PreventDropTable
ON DATABASE
FOR DROP_TABLE
AS
BEGIN
PRINT 'Nije dozvoljeno brisanje tabela u ovoj bazi podataka!';
ROLLBACK; -- Poništava DROP komandu
END;
🎯 Praktična Vježba: Pametna Validacija
Zadatak: Zaštita od masovne katastrofe
Vaša agencija želi spriječiti da bilo ko obriše više od 10 izvještaja odjednom (kako bi se spriječili "accidental" deletions miliona redova).
CREATE TRIGGER trg_SafeDeleteReports
ON Stats.Reports
AFTER DELETE
AS
BEGIN
DECLARE @Count INT = (SELECT COUNT(*) FROM deleted);
IF @Count > 10
BEGIN
RAISERROR('Brisanje više od 10 izvještaja odjednom je zabranjeno iz sigurnosnih razloga.', 16, 1);
ROLLBACK TRANSACTION;
END
END;
GO
⚙️ Performanse i Opasnosti
- Skrivena cijena: Svaki triger produžava trajanje transakcije. Ako triger traje dugo, cijela aplikacija će biti spora.
- Rekurzija: Triger na tabeli A koji mijenja tabelu B, na kojoj postoji triger koji mijenja tabelu A, može uzrokovati beskonačnu petlju.
- Teško debagiranje: Developer vidi
UPDATEupit, ali ne vidi 5 trigera koji se "vrte" u pozadini. Uvijek dokumentujte trigere!
✅ Zaključak
Trigeri su moćan, ali opasan alat:
- ✅ Koristite ih za Auditing i sigurnosna pravila koja se ne mogu riješiti kroz Constraints.
- ✅ Pišite kod koji radi sa setovima podataka (magic tables).
- ✅ Izbjegavajte tešku logiku unutar trigera - ako može, napravite to u Stored Proceduri.
📚 Sljedeća Lekcija
U Lekciji 3.5 prelazimo na najnapredniji dio programabilnosti: CLR Integration. Naučićete kako izvršiti .NET kod (C#) direktno unutar SQL Servera za stvari koje T-SQL jednostavno ne može uraditi.