Автоматизация на процесите и запазване на цялостта на данните
Тригерът е специален вид съхранена процедура, която се стартира автоматично (задейства се), когато се случи определено събитие в базата данни.
Не можете да извикате тригер ръчно. Той чака "в засада" някой да промени данните.
BEFORE (преди записа) или AFTER (след записа).INSERT, UPDATE или DELETE.Вътре в тригера имаме достъп до виртуални променливи, които съдържат данните от реда, който обработваме.
| Променлива | Описание | Налична при |
|---|---|---|
NEW.column_name |
Новата стойност, която се опитваме да запишем. | INSERT, UPDATE |
OLD.column_name |
Старата стойност, която е била в базата преди промяната. | UPDATE, DELETE |
Искате да направите лог (архив) на старата заплата на служител, преди тя да бъде променена. Коя променлива ще използвате, за да вземете текущата (стара) заплата?
Използваме BEFORE, когато искаме да проверим данните преди те да влязат в базата. Ако не ни харесват, можем да ги променим или да спрем заявката.
Задача: Не позволявай заплатата да бъде отрицателно число. Ако някой въведе -500, направи го 0.
CREATE TRIGGER check_salary_positive
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
IF NEW.salary < 0 THEN
SET NEW.salary = 0;
END IF;
END;
Защо използваме BEFORE в този случай, а не AFTER?
Най-честата употреба на тригери е за Audit Logs. Когато някой изтрие или промени нещо, ние записваме "кой, какво и кога" в друга таблица.
Задача: Когато се изтрие служител, запиши името му в таблица deleted_employees_log.
CREATE TRIGGER log_employee_deletion
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
INSERT INTO deleted_employees_log (emp_name, date_deleted)
VALUES (OLD.first_name, NOW());
END;
Напишете тригер, който се задейства при обновяване (UPDATE) на таблицата products. Тригерът трябва да проверява дали новата цена (price) е по-висока от старата с повече от 100%. Ако е така, задайте новата цена да бъде старата цена + 10% (автоматична корекция).
CREATE TRIGGER prevent_price_hike
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
IF NEW.price > OLD.price * 2 THEN
SET NEW.price = OLD.price * 1.10;
END IF;
END;
Имате таблица tasks с колона completed_at (дата на завършване). Напишете тригер, който: при UPDATE на статус status = 'DONE', автоматично записва текущото време (NOW()) в колоната completed_at.
CREATE TRIGGER set_completion_date
BEFORE UPDATE ON tasks
FOR EACH ROW
BEGIN
IF NEW.status = 'DONE' AND OLD.status != 'DONE' THEN
SET NEW.completed_at = NOW();
END IF;
END;
Тези задачи изискват да комбинирате логика и синтаксис. За всяка задача има предоставена структура на таблиците.
Сценарий: Работите по банков софтуер. Имате таблица accounts с колони id, owner и balance.
Цел: Напишете тригер, който не позволява теглене на пари, ако балансът стане отрицателен. Ако след транзакцията балансът е под 0, тригерът трябва да върне баланса към старата му стойност (да отмени промяната).
Сценарий: В онлайн магазин искаме да следим как се променят цените на стоките във времето.
Цел: Създайте тригер, който при всяка промяна на цената в таблица products, записва старата цена, новата цена и датата на промяна в таблица price_history.
Сценарий: В таблицата със служители има запис с позиция 'CEO' (Изпълнителен директор).
Цел: Напишете тригер, който предотвратява изтриването (DELETE) на служител, ако неговата длъжност (position) е 'CEO'. Ако някой се опита да го изтрие, тригерът трябва да хвърли грешка (или да използваме "трик" за MySQL, ако не ползваме SIGNAL - например да променим ID-то на невалидно, но тук ще ползваме SIGNAL SQLSTATE за пълнота).