CodeGym /Kurslar /SQL SELF /PostgreSQL-də trigger tipləri: BEFORE, AFTER, INSTEAD OF

PostgreSQL-də trigger tipləri: BEFORE, AFTER, INSTEAD OF

SQL SELF
Səviyyə , Dərs
Mövcuddur

PostgreSQL-də triggerlər üç əsas kateqoriyaya bölünür:

  1. BEFORE — əsas əməliyyat yerinə yetirilməzdən əvvəl işə düşür (məsələn, INSERT, UPDATE və ya DELETE qabağı). Onlardan istifadə edərək əməliyyatın qarşısını ala və ya məlumatları saxlanmazdan əvvəl dəyişə bilərsən.

  2. AFTER — əsas əməliyyat tamamlandıqdan sonra işə düşür. Bu tip adətən log yazmaq, əlaqəli qeydlər yaratmaq və ya əməliyyatın uğurla bitməsindən asılı olan hərəkətləri yerinə yetirmək üçün istifadə olunur.

  3. INSTEAD OF — faktiki əməliyyat əvəzinə işə düşür. Yalnız view-lar üçün istifadə olunur. Məsələn, istifadəçi view-a məlumat əlavə etməyə çalışanda, bu prosesi INSTEAD OF trigger ilə idarə edə bilərsən.

BEFORE triggeri

BEFORE triggerləri PostgreSQL əsas əməliyyatı yerinə yetirməzdən əvvəl işə düşür. Əgər məlumatları saxlamazdan əvvəl yoxlamaq və ya dəyişmək istəyirsənsə, çox faydalıdır. Təsəvvür elə, bu elə bil təyyarəyə minməzdən əvvəl baqaj yoxlaması kimidir: əgər baqaj uyğun gəlmirsə, onu dəyişmək və ya ümumiyyətlə bloklamaq olar.

Gəlin, insert zamanı məlumatların doğruluğunu yoxlayan bir nümunəyə baxaq. Deyək ki, bizdə students adlı bir cədvəl var və burada tələbələr haqqında məlumat saxlayırıq. İstəyirik ki, tələbənin yaşı 100-dən çox olmasın (çox real deyil, düzdür).

Cədvəli yaradırıq:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    age INT NOT NULL
);

Trigger üçün funksiya yaradırıq:

CREATE OR REPLACE FUNCTION validate_age()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.age > 100 THEN
        RAISE EXCEPTION 'Tələbənin yaşı 100-dən çox ola bilməz!';
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Trigger yaradırıq:

CREATE TRIGGER before_insert_students
BEFORE INSERT ON students
FOR EACH ROW
EXECUTE FUNCTION validate_age();

İndi, əgər sən 100-dən böyük yaşla tələbə əlavə etməyə çalışsan, PostgreSQL xəta verəcək:

INSERT INTO students (name, age) VALUES ('İvan İvanov', 120);
-- Xəta: Tələbənin yaşı 100-dən çox ola bilməz!

Bax belə bir yoxlama!

AFTER triggeri

AFTER triggerləri əsas əməliyyat uğurla başa çatdıqdan sonra işə düşür. Əməliyyatın nəticəsindən asılı olan hərəkətləri yerinə yetirmək üçün faydalıdır. Məsələn, log yazmaq və ya əlaqəli qeydlər yaratmaq üçün.

Ssenari: bizdə students cədvəli var və bütün dəyişiklikləri ayrıca log cədvəlinə yazmaq istəyirik.

Log üçün cədvəl yaradırıq:

CREATE TABLE students_log (
    id SERIAL PRIMARY KEY,
    student_id INT,
    operation TEXT,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Trigger üçün funksiya yaradırıq:

CREATE OR REPLACE FUNCTION log_student_changes()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO students_log (student_id, operation)
    VALUES (NEW.id, TG_OP);  -- TG_OP əməliyyat tipini saxlayır: INSERT, UPDATE və ya DELETE
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Trigger yaradırıq:

CREATE TRIGGER after_insert_students
AFTER INSERT ON students
FOR EACH ROW
EXECUTE FUNCTION log_student_changes();

İndi yeni tələbə əlavə edəndə, PostgreSQL avtomatik olaraq əməliyyatı log-a yazacaq:

INSERT INTO students (name, age) VALUES ('Anna Linq', 22);

SELECT * FROM students_log;
-- Nəticə:
-- id | student_id | operation |        timestamp
--  1 |          1 | INSERT    | 2023-11-15 12:00:00

INSTEAD OF triggeri

INSTEAD OF triggerləri əməliyyat yerinə yetirilməzdən əvvəl yox, onun əvəzinə işə düşür. Bu, yalnız view-lar üçün istifadə oluna bilən yeganə trigger tipidir. View-lar üzərində birbaşa əməliyyat aparmaq mümkün olmadıqda, bu triggerlər çox rahatdır.

Ssenari: bizdə iki cədvəl var — coursesteachers. Onları birləşdirən view yaradacağıq və bu view üzərindən insert əməliyyatını idarə edən trigger yazacağıq.

Cədvəlləri yaradırıq:

CREATE TABLE courses (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    teacher_id INT NOT NULL
);

CREATE TABLE teachers (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

View yaradırıq:

CREATE VIEW course_details AS
SELECT 
    courses.id AS course_id,
    courses.name AS course_name,
    teachers.name AS teacher_name
FROM courses
JOIN teachers ON courses.teacher_id = teachers.id;

Problem: view-a birbaşa məlumat əlavə edə bilmirik, çünki o, iki cədvəldən məlumatları birləşdirir. Həll: INSTEAD OF trigger istifadə edirik.

Trigger üçün funksiya yaradırıq:

CREATE OR REPLACE FUNCTION insert_course_details()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO teachers (name) VALUES (NEW.teacher_name) RETURNING id INTO NEW.teacher_id;
    INSERT INTO courses (name, teacher_id) VALUES (NEW.course_name, NEW.teacher_id);
    RETURN NULL;  -- View-da məlumat saxlanmır
END;
$$ LANGUAGE plpgsql;

Trigger yaradırıq:

CREATE TRIGGER instead_of_insert_course_details
INSTEAD OF INSERT ON course_details
FOR EACH ROW
EXECUTE FUNCTION insert_course_details();

İndi məlumatı birbaşa view-a əlavə edə bilərsən:

INSERT INTO course_details (course_name, teacher_name)
VALUES ('Riyaziyyat', 'Aleks Minq');

SELECT * FROM courses;
-- Nəticə:
-- id | name        | teacher_id
--  1 | Riyaziyyat  | 1

SELECT * FROM teachers;
-- Nəticə:
-- id | name
--  1 | Aleks Minq

Trigger tiplərinin müqayisəsi

Trigger tipi Nə vaxt işə düşür Əsas istifadə sahəsi
BEFORE Əməliyyatdan əvvəl Doğrulama, məlumatların hazırlanması
AFTER Uğurlu başa çatdıqdan sonra Log yazmaq, əlaqəli məlumatların yenilənməsi
INSTEAD OF Əməliyyat əvəzinə View-larda əməliyyatların işlənməsi

Xüsusiyyətlər və məhdudiyyətlər

BEFORE triggerləri əməliyyatdan əvvəl məlumatları dəyişə bilər. Məsələn, adları avtomatik olaraq böyük hərflə yaza bilərsən.

AFTER triggerləri məlumatlara təsir edə bilmir, çünki əməliyyat artıq başa çatıb. Onlar yalnız sonrakı hərəkətlər üçündür.

INSTEAD OF triggerləri yalnız view-lara tətbiq olunur. Onlar bir neçə əlaqəli cədvəldə mürəkkəb insert/update məntiqini reallaşdırmağa imkan verir.

Bu günlük bu qədər! Əgər BEFORE, AFTERINSTEAD OF bir az çətin görünürsə, narahat olma. Əsas odur ki, onların əsas prinsiplərini və istifadə ssenarilərini yadında saxla. Bir neçə nümunəni özün yazmağa çalış, material daha yaxşı yadda qalacaq.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION