Vấn đề: Tự động kiểm tra/ràng buộc trước khi chèn dữ liệu
Cần ngăn chặn INSERT nếu tổng cột Value trong bảng đã đạt 60.
Giải pháp: Trigger BEFORE INSERT
Trigger kích hoạt trước mỗi hàng chèn (FOR EACH ROW). Dùng SIGNAL để ném lỗi và hủy chèn.
1. Cú pháp tạo Trigger
DELIMITER //
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
-- logic kiểm tra
IF (condition) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error message';
END IF;
END //
DELIMITER ;
2. Ví dụ cụ thể: Tổng Value không vượt quá 60
CREATE TABLE DemoTable (Value INT);
DELIMITER //
CREATE TRIGGER sum_is_60
BEFORE INSERT ON DemoTable
FOR EACH ROW
BEGIN
DECLARE custom_message VARCHAR(256);
IF (SELECT SUM(Value) FROM DemoTable) = 60 THEN
SET custom_message = 'Cannot insert: sum(Value) would exceed 60';
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = custom_message;
END IF;
END //
DELIMITER ;
3. Kiểm tra Trigger
INSERT INTO DemoTable VALUES (10); -- OK, sum=10
INSERT INTO DemoTable VALUES (20); -- OK, sum=30
INSERT INTO DemoTable VALUES (30); -- OK, sum=60
INSERT INTO DemoTable VALUES (40); -- LỖI: sum sẽ thành 100 > 60
4. Kết quả lỗi
ERROR 1644 (45000): Cannot insert: sum(Value) would exceed 60
Giải thích
BEFORE INSERT– Chạy trước khi hàng được ghi vào bảng.FOR EACH ROW– Chạy cho mỗi hàng INSERT (INSERT nhiều hàng → trigger chạy nhiều lần).NEW.Value– Truy cập giá trị mới sắp chèn (ví dụ:IF (SELECT SUM(Value) FROM DemoTable) + NEW.Value > 60chính xác hơn).SIGNAL SQLSTATE '45000'– Ném ngoại lệ người dùng tự định nghĩa (45000 = unhandled user-defined exception).
Cải tiến logic chính xác hơn
IF (SELECT COALESCE(SUM(Value), 0) FROM DemoTable) + NEW.Value > 60 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sum would exceed 60';
END IF;
Dùng COALESCE xử lý bảng rỗng (SUM trả NULL). Cộng NEW.Value để kiểm tra sau khi chèn.
Lưu ý
- Trigger làm chậm INSERT – chỉ dùng khi cần thiết (ràng buộc phức tạp không thể dùng CHECK constraint).
- MySQL 8.0.16+ hỗ trợ
CHECK constraint– ưu tiên dùng cho ràng buộc đơn giản. - Xem trigger:
SHOW TRIGGERS;hoặcSELECT * FROM information_schema.triggers;.