Пара заметок:
Триггер не может выдать UPDATE для таблицы, которая сработала, это запрещено.
Неквалифицированные ссылки (например, FUSDate1
и FUZDate1
) недействительны. Эти ссылки ни к чему не привели.
Ссылка на OLD.FUSDate1
недопустима в контексте триггера AFTER INSERT. В триггере UPDATE OLD.col
относится к значению col перед обновлением.
Выражение (FUZDate1=OLD.FUSDate1)
не является присваиванием, это сравнение, которое должно вернуть 0, 1 или NULL.
Если мы хотим запустить UPDATE
и INSERT
, для этого потребуется два отдельных триггера.
Если мы хотим изменить содержимое текущей строки, мы можем использовать триггер BEFORE
вместо AFTER
.
Я хочу обновить существующую строку после вставки или обновления.
Было бы намного проще применить изменения до строки, вставленной или обновленной. Мы можем присвоить значение столбцу col
, ссылаясь на NEW.col
в присваивании в триггере BEFORE INSERT
или BEFORE UPDATE
. Например:
SET NEW.col = expr;
Не изменяйте FUSDate1
или FUSDate2
Если я ничего не добавил к FUSDate1
или FUSDate2
Это кажется довольно простым. Только не назначайте NEW.FUSDate1
или NEW.FUSDate2
.
Обновите FUSDate на новую или вставленную, если я обновил или вставил данные в FUSDate
Пример предлагаемого триггера содержит ссылки на FUZDate1
или FUZDate2
, но в спецификации эти столбцы не упоминаются. Спецификация сбивает с толку.
Оператор UPDATE
назначит значение столбцу, для этого не требуется триггер. Оператор INSERT
может присвоить значение столбцу, опять же, для этого не требуется триггер.
Спецификация не ясна. Предоставление примера начального состояния (строки в таблице) и пример операторов INSERT или UPDATE, а также желаемое состояние после выполнения оператора будут иметь большое значение для разъяснения требований.
Демонстрация триггера BEFORE UPDATE
, который предотвращает присвоение нового значения определенному столбцу:
DELIMITER $$
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- detect a change made to a value in col
IF OLD.col <=> NEW.col THEN
-- value of col is not changed, so do nothing
DO 0;
ELSE
-- we detected a new value was assigned to col
IF OLD.col IS NOT NULL THEN
-- we can override the new value, keep it the same
SET NEW.col = OLD.col;
END IF;
END IF;
END$$
DELIMITER ;
Для достижения этого примера триггера нам не нужно столько условий IF
; они включены в качестве демонстрации некоторых проверок, которые мы можем выполнить, как мы можем сделать ссылки на существующее значение col
и новое значение, присвоенное col
.
Followup
Основываясь на информации об обновлении в вопросе, вот пример BEFORE UPDATE
триггера, который удовлетворяет спецификации.
Это для действия UPDATE
. Чтобы получить то же самое поведение с оператором INSERT
, это определение триггера необходимо повторить, с BEFORE INSERT
вместо BEFORE UPDATE
.
(я бы использовал имя _bu
для триггера перед обновлением и _bi
для триггера перед вставкой.)
DELIMITER $$
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- set one of the `fusdateN` columns to current date
-- which column to set depends on the value assigned to `fus`
IF NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
ELSEIF NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
ELSEIF NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END IF;
END$$
DELIMITER ;
второе наблюдение
Чтобы ответить на вопрос об использовании оператора CASE WHEN
в контексте хранимой программы MySQL ...
Мы могли бы реализовать пример триггера (прямо выше в этом ответе), заменив IF-THEM
любой из двух форм оператора CASE
.
либо
CASE
WHEN NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
WHEN NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
WHEN NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END CASE;
-или-
CASE NEW.fus
WHEN 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
WHEN 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
WHEN 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END CASE;
примечание
Оператор CASE
доступен в хранимых программах MySQL; вне хранимой программы это не допустимый оператор SQL.
Кроме того, мы не должны путать это выражение CASE с выражением CASE . Выражение CASE является действительным в контексте оператора SQL, такого как оператор SELECT
или UPDATE
.
ДЕМОНСТРАЦИЯ
"Я исследовал триггер, но, к сожалению, ничего не сохраняет в fusDates."
@ Кристиано: вот простая демонстрация
создать таблицу
CREATE TABLE `safety_certification`
( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, fus VARCHAR(5)
, fusdate1 DATE
, fusdate2 DATE
, fusdate3 DATE
) ENGINE=INNODB
;
заполнить таблицу демонстрационными строками
INSERT INTO `safety_certification` (id, fus, fusdate1, fusdate2, fusdate3) VALUES
( 1, '', NULL, NULL, NULL)
,( 2, '', NULL, NULL, NULL)
,( 3, '', NULL, NULL, NULL)
,( 4, '', NULL, NULL, NULL)
,( 5, '', NULL, NULL, NULL)
;
создать триггер
DELIMITER $$
CREATE TRIGGER `safety_certification_bu`
BEFORE UPDATE ON `safety_certification`
FOR EACH ROW
BEGIN
-- set one of the `fusdateN` columns to current date
-- which column to set depends on the value assigned to `fus`
IF NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
ELSEIF NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
ELSEIF NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END IF;
END$$
DELIMITER ;
обновления будут выполнять ПЕРЕД ОБНОВЛЕНИЕМ триггера, который мы только что определили
UPDATE `safety_certification` sc SET sc.fus = 'FUS1' WHERE sc.id = 1 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS2' WHERE sc.id = 2 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS3' WHERE sc.id = 3 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS4' WHERE sc.id = 4 ;
показать содержимое таблицы
SELECT * FROM `safety_certification`;
возвращается:
id fus fusdate1 fusdate2 fusdate3
------ ------ ---------- ---------- ------------
1 FUS1 2018-05-04 (NULL) (NULL)
2 FUS2 (NULL) 2018-05-04 (NULL)
3 FUS3 (NULL) (NULL) 2018-05-04
4 FUS4 (NULL) (NULL) (NULL)
5 (NULL) (NULL) (NULL)
похоже, что триггер заполняет столбцы fusdate1, fusdate2 и fusdate3 в соответствии со спецификацией, когда некоторые конкретные значения назначены для fus