Żeby stworzyć trigger w PostgreSQL, musisz określić następujące elementy:
- Nazwę triggera.
- Typ zdarzenia (
INSERT,UPDATE,DELETE). - Moment wykonania (
BEFOREalboAFTER). - Tabelę, do której się odnosi.
- Funkcję, która zostanie wykonana (w PL/pgSQL lub innym języku).
Oto ogólna struktura komendy:
CREATE TRIGGER nazwa_triggera
[BEFORE | AFTER] {INSERT | UPDATE | DELETE}
ON nazwa_tabeli
[FOR EACH ROW | FOR EACH STATEMENT]
WHEN (warunek)
EXECUTE FUNCTION nazwa_funkcji();
Przykład prostego triggera
Stwórzmy bazową tabelę students i dodajmy trigger, który odpala się po dodaniu nowego rekordu.
Na początek tworzymy tabelę students
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Co tu się dzieje? Stworzyliśmy tabelę z polami id, name i last_modified. Pole last_modified będzie przechowywać datę i godzinę ostatniej modyfikacji rekordu.
Triggery są zawsze powiązane z funkcjami. Najpierw napiszemy prostą funkcję, która będzie aktualizować pole last_modified przy każdym dodaniu rekordu:
CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
-- Ustawiamy aktualną datę i godzinę w polu last_modified
NEW.last_modified := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Co to za magia?
NEW— specjalna zmienna, która przechowuje nowe wartości wiersza (dla zdarzeńINSERTlubUPDATE).CURRENT_TIMESTAMP— funkcja zwracająca aktualną datę i godzinę.RETURN NEW— zwraca zmodyfikowany wiersz do dalszego zapisania.
Teraz tworzymy sam trigger:
CREATE TRIGGER set_last_modified
AFTER INSERT
ON students
FOR EACH ROW
EXECUTE FUNCTION update_last_modified();
Rozszyfrowanie:
AFTER INSERT: trigger odpala się po dodaniu nowego wiersza.ON students: trigger dotyczy tabelistudents.FOR EACH ROW: trigger działa dla każdego nowego wiersza.EXECUTE FUNCTION: wskazuje, jaką funkcję wywołać.
Sprawdzanie działania triggera
Sprawdźmy, jak działa nasz trigger:
INSERT INTO students (name) VALUES ('Alice');
SELECT * FROM students;
Zobaczysz mniej więcej taki wynik:
| id | name | last_modified |
|---|---|---|
| 1 | Alice | 2023-10-15 14:23:45 |
Trigger automatycznie zaktualizował pole last_modified. Magia? Nie, po prostu PostgreSQL.
Użycie warunków z WHEN
Czasem chcesz, żeby trigger odpalał się nie zawsze, tylko przy określonych warunkach. Do tego służy słowo kluczowe WHEN.
Zobaczmy przykład, gdzie trigger działa tylko dla określonych wartości.
Załóżmy, że chcemy, żeby trigger odpalał się tylko dla studentów o imieniu "Alice". Zmieniamy nasz trigger:
CREATE OR REPLACE FUNCTION update_last_modified_condition()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_modified := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_last_modified_condition
AFTER INSERT
ON students
FOR EACH ROW
WHEN (NEW.name = 'Alice')
EXECUTE FUNCTION update_last_modified_condition();
Teraz trigger zaktualizuje pole last_modified tylko dla studentów o imieniu "Alice".
Sprawdźmy:
INSERT INTO students (name) VALUES ('Alice');
INSERT INTO students (name) VALUES ('Bob');
SELECT * FROM students;
Wynik:
| id | name | last_modified |
|---|---|---|
| 1 | Alice | 2023-10-15 14:30:00 |
| 2 | Bob | (NULL) |
Zwróć uwagę: dla studenta "Bob" pole last_modified zostało puste, bo trigger się nie odpalił.
Powiązanie triggera z funkcją: EXECUTE FUNCTION
Funkcja to serce każdego triggera. Trigger nie może istnieć bez funkcji, która określa jego logikę. W PostgreSQL funkcje można pisać w PL/pgSQL lub innych wspieranych językach, jak Python czy C.
Pokażmy przykład użycia funkcji PL/pgSQL.
Stwórzmy funkcję, która loguje zmiany w osobnej tabeli audit_log.
Najpierw tworzymy tabelę audit_log
CREATE TABLE audit_log (
id SERIAL PRIMARY KEY,
operation TEXT NOT NULL,
student_id INTEGER NOT NULL,
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
A teraz – funkcja:
CREATE OR REPLACE FUNCTION log_insert()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (operation, student_id)
VALUES ('INSERT', NEW.id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Teraz piszemy trigger:
CREATE TRIGGER log_student_insert
AFTER INSERT
ON students
FOR EACH ROW
EXECUTE FUNCTION log_insert();
I sprawdzamy działanie:
INSERT INTO students (name) VALUES ('Charlie');
SELECT * FROM audit_log;
Zobaczysz mniej więcej taki wynik:
| id | operation | student_id | log_time |
|---|---|---|---|
| 1 | INSERT | 3 | 2023-10-15 14:35:00 |
Trigger automatycznie zapisał log o nowym rekordzie.
Błędy i specyfika pracy z triggerami
Błąd: brak funkcji. Jeśli spróbujesz stworzyć trigger bez funkcji, PostgreSQL wyrzuci błąd. Zawsze najpierw twórz funkcję, potem trigger.
Problemy z wydajnością. Duża liczba triggerów albo skomplikowane funkcje mogą spowolnić bazę danych. Używaj ich z głową.
Rekursja. Jeśli trigger zmienia coś w tej samej tabeli, na której działa, może to wywołać nieskończoną pętlę. Używaj warunków WHEN, żeby tego uniknąć.
GO TO FULL VERSION