CodeGym /Các khóa học /SQL SELF /Trigger tự động cập nhật trường last_modified

Trigger tự động cập nhật trường last_modified khi thay đổi bản ghi

SQL SELF
Mức độ , Bài học
Có sẵn

Giả sử bạn đang code một app quản lý sinh viên và khóa học, và bạn có bảng students. Trong bảng này có trường last_modified, trường này cần tự động cập nhật mỗi khi có thay đổi dữ liệu trong bản ghi (ví dụ đổi tên sinh viên hoặc tuổi của họ).

Thay vì phải tự tay viết update last_modified trong từng câu lệnh SQL, mình sẽ tạo một trigger để nó tự làm cho mình.

Cấu trúc bảng students

Đầu tiên, mình sẽ tạo bảng students để dùng làm ví dụ. Bảng này chứa info cơ bản về sinh viên:

CREATE TABLE students (
    student_id SERIAL PRIMARY KEY, -- Định danh duy nhất của sinh viên
    name VARCHAR(100) NOT NULL,   -- Tên sinh viên
    age INT,                      -- Tuổi sinh viên
    last_modified TIMESTAMP NOT NULL DEFAULT NOW() -- Thời gian thay đổi gần nhất
);
  • Trường last_modified ban đầu sẽ được set bằng thời gian hiện tại (NOW()) khi tạo bản ghi.
  • Trường này sẽ tự động cập nhật khi dữ liệu sinh viên thay đổi.

Giờ mình sẽ insert một số dữ liệu test vào bảng:

INSERT INTO students (name, age)
VALUES 
    ('Otto Lin', 20),
    ('Maria Chi', 22),
    ('Alex Song', 19);

Bây giờ dữ liệu trong bảng sẽ như sau:

student_id name age last_modified
1 Otto Lin 20 2023-10-15 12:00:00
2 Maria Chi 22 2023-10-15 12:00:00
3 Alex Song 19 2023-10-15 12:00:00

Tạo function để cập nhật last_modified

Function bằng PL/pgSQL sẽ được trigger gọi để update giá trị trường last_modified. Nó sẽ tự động chạy trước khi update bản ghi.

Tạo function update_last_modified nhé:

CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
    -- Cập nhật trường last_modified thành thời gian hiện tại
    NEW.last_modified := NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
  • NEW — là biến đặc biệt chứa dữ liệu mới của bản ghi (sau khi thay đổi).
  • Mình set NEW.last_modified bằng NOW() (ngày giờ hiện tại).
  • Function trả về biến NEW đã được cập nhật, cần thiết để trigger hoạt động đúng.

Tạo trigger

Giờ mình sẽ tạo trigger để tự động gọi function update_last_modified mỗi khi update bản ghi trong bảng students.

CREATE TRIGGER set_last_modified
BEFORE UPDATE ON students
FOR EACH ROW
EXECUTE FUNCTION update_last_modified();

Ở đây có gì:

  • BEFORE UPDATE nghĩa là trigger chạy trước khi thực hiện update.
  • FOR EACH ROW nghĩa là trigger chạy cho từng dòng bị thay đổi.
  • EXECUTE FUNCTION update_last_modified() là gọi function update_last_modified.

Test trigger

Giờ mình thử xem trigger chạy thế nào nhé. Lấy dữ liệu hiện tại từ bảng students:

SELECT * FROM students;

Kết quả:

student_id name age last_modified
1 Otto Lin 20 2023-10-15 12:00:00
2 Maria Chi 22 2023-10-15 12:00:00
3 Alex Song 19 2023-10-15 12:00:00

Giờ mình update tuổi của sinh viên có student_id = 1:

UPDATE students
SET age = 21
WHERE student_id = 1;

Lấy lại dữ liệu từ bảng:

SELECT * FROM students;

Kết quả mong đợi:

student_id name age last_modified
1 Otto Lin 21 2023-10-15 14:00:00
2 Maria Chi 22 2023-10-15 12:00:00
3 Alex Song 19 2023-10-15 12:00:00

Lưu ý: trường last_modified của bản ghi có student_id = 1 đã được cập nhật thành thời gian hiện tại, còn các bản ghi khác thì không đổi.

Mở rộng logic trigger

Giả sử giờ bạn muốn trường last_modified chỉ cập nhật khi thay đổi một số cột nhất định. Ví dụ, chỉ khi tên sinh viên hoặc tuổi thay đổi thì trigger mới chạy, còn thay đổi khác thì không.

Để làm vậy, bạn có thể thêm điều kiện với toán tử WHEN trong định nghĩa trigger.

Tạo trigger mới có điều kiện nhé:

DROP TRIGGER IF EXISTS set_last_modified ON students;

CREATE TRIGGER set_last_modified
BEFORE UPDATE ON students
FOR EACH ROW
WHEN (OLD.name IS DISTINCT FROM NEW.name OR OLD.age IS DISTINCT FROM NEW.age)
EXECUTE FUNCTION update_last_modified();

Ở đây:

  • Điều kiện WHEN kiểm tra xem giá trị cũ (OLD) có khác giá trị mới (NEW) ở cột name hoặc age không.
  • Nếu không có cột nào trong hai cột này thay đổi thì trigger sẽ không chạy.

Thử update lại dữ liệu trong bảng và test logic mới nhé.

Tips khi dùng trigger

  1. Đừng lạm dụng trigger. Dùng thì tiện thật, nhưng có thể làm logic database phức tạp và khó debug hơn.
  2. Luôn ghi chú rõ trigger dùng để làm gì, cho trường hợp nào.
  3. Dùng điều kiện WHEN để hạn chế trigger chạy lung tung không cần thiết.
  4. Nhớ là trigger có thể ảnh hưởng đến hiệu năng database, nhất là khi bảng có nhiều bản ghi.

Lỗi phổ biến khi làm việc với trigger

Thay đổi dữ liệu sai. Ví dụ, quên set giá trị cho NEW và trả về dữ liệu gốc không thay đổi gì.

Điều kiện sai. Ví dụ, quên thêm điều kiện WHEN, trigger chạy cả khi không cần update gì.

Đệ quy. Nếu trigger gọi function mà function lại gọi trigger, có thể tạo vòng lặp vô hạn. PostgreSQL có bảo vệ chống đệ quy, nhưng tốt nhất là tránh trường hợp này.

Ví dụ này cho thấy dùng trigger có thể giúp tự động hóa việc cập nhật dữ liệu rất tiện. Trong thực tế, kỹ thuật này thường dùng để log thay đổi, đảm bảo toàn vẹn dữ liệu và tự động hóa các thao tác lặp đi lặp lại.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION