Я попытался создать нижеприведенный триггер, но у меня возникла ошибка. Могу ли я использовать «Обновление» или «случай, когда» в триггере? Пожалуйста, помогите мне решить мою проблему здесь.
Пояснение к коду: Я хочу обновить существующую строку после вставки или обновления. Не меняйте «FUSDate1» или «FUSDate2», если я ничего не добавил к «FUSDate1» или «FUSDate2».
Обновите FUSDate до нового или вставленного, если я обновил или вставил данные в FUSDate
Код:
delimiter //
create trigger SafetyCertificationTRG
after insert on SafetyCertification
for each row
begin
case when (FUSDate1='' or FUZDate1 is NULL) then (FUZDate1=OLD.FUSDate1) else (update SafetyCertification set FUZDate1=NEW.FUSDate1) end;
case when (FUSDate2='' or FUZDate2 is NULL) then (FUZDate2=NEW.FUSDate2) else (update SafetyCertification set FUZDate2=NEW.FUSDate2) end;
end //
delimiter ;
Обновлено: я собираюсь добавить сюда некоторую информацию, чтобы сделать вопрос более ясным.
У меня есть один столбец как FUS, в котором можно получить только эти 3 значения :( 'FUS1', 'FUS2' и 'FUS3') У меня есть еще 3 столбца: FUSDate1, FUSDate2, FUSDate3.
Я хочу сохранить текущую дату в FUSDate1, FUSDate2 или FUSDate3 в зависимости от пользовательского выбора FUS. (Они находятся в одной таблице)
Я использовал предоставленный ответ и изменил его на это, но я не могу сделать то, что описано выше.
Код: этот код предназначен только для FUS1 и FUSDate1.
delimiter //
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- detect a change made to a value in col
IF OLD.FUS <=> NEW.FUS THEN
-- value of col is not changed, so do nothing
DO 0;
ELSE
-- we detected a new value was assigned to col
IF OLD.FUS ='%FUS1%' THEN
-- we can override the new value, keep it the same
SET NEW.FUSDate1 = CURDATE();
END IF;
END IF;
END //
delimiter ;
Другой код, который, как я ожидал, выполняет свою работу, но все еще имеет проблему, не обновляется, как указано выше. Код:
delimiter //
CREATE TRIGGER SafetyCertification_bu
BEFORE INSERT ON SafetyCertification
FOR EACH ROW
BEGIN
IF NEW.FUS='%FUS1%' THEN
SET new.FUSDate1=MD5(CURDATE());
END IF;
END //
delimiter ;
Обновление 3:
Третий код, представленный в ответе, ничего не добавляет к FUSdate1 и 2 и 3, когда я обновляю или вставляю какие-либо данные.
Код
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 ;
Раньше у меня был такой же вопрос. Хороший вопрос
@Uueerdo Итак, что мне делать в этом случае? Есть ли у вас какие-нибудь рекомендации?
@kiarash Удалось найти какое-нибудь решение?
@christiano Я нашел глупое и низкопроизводительное решение, я создаю два триггера, один для другой таблицы, и я создаю второй триггер для вставки данных в первую таблицу. Не уверен, есть ли другой способ
@Christiano вам понадобится несколько запросов вне триггера; это можно сделать на процедурном языке процесса, выполнившего инициируемый вами запрос, или же инициирующий запрос можно заменить хранимой процедурой, которая выполняет этот запрос и любые необходимые последующие запросы.
некоторые примечания: при сравнении равенства символы процента в литерале являются буквальными символами, а не подстановочными знаками, как при сравнении LIKE. То есть 'abc' = '%abc%' оценивается как 0 (ложь), 'abc' LIKE '%abc%' оценивается как 1 (истина). В последнем примере представлена функция MD5, без объяснения причин ее использования.






У меня была такая же проблема, и я использовал два триггера, Первый триггер отправляет данные в другую таблицу, поэтому теперь вы можете создать еще один триггер для отправки этих данных в первую таблицу. Я думаю, что это низкая производительность, но это единственный способ, которым я ее добился. Я надеюсь, что у других есть другое решение для вас.
Похоже, это могло быть немного нестабильно; просто убедитесь, что второй триггер не запускает повторно первый триггер, иначе вы можете столкнуться с проблемами рекурсии.
Пара замечаний:
Триггер не может выполнить ОБНОВЛЕНИЕ для таблицы, запустившей триггер, это запрещено.
Неквалифицированные ссылки (например, 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.
СЛЕДОВАТЬ ЗА
Основываясь на информации об обновлении в вопросе, вот пример триггера 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.
ДЕМОНСТРАЦИЯ
«Я исследовал Trigger, но, к сожалению, ничего не сохраняет в fusDates».
@Christiano: вот простая демонстрация
создать таблицу
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, который мы только что определили
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
Вау, спасибо большое,
Я работал над этим и предоставил редакцию в своем вопросе. У меня все еще есть проблема.
FOLLOWUP добавляется к ответу, предоставляет пример определения триггера, который удовлетворяет спецификации, приведенной в правках к вопросу.
добавлено второе продолжение, чтобы ответить на вопрос в заголовке, используя оператор CASE WHEN
Большое спасибо за вашу помощь, я очень ценю ваше время. Я буду работать над этим и сделаю это как лучший ответ. Пожалуйста, дайте мне время поработать над этим.
Осмотрел Trigger, но в fusDates к сожалению ничего не сохраняет.
@Christiano: Я добавил к ответу ДЕМОНСТРАЦИЯ, чтобы показать, что триггер BEFORE UPDATE выполняет указанные операции.
Большое вам спасибо. Кажется, у меня проблема с моим MYSQL, поскольку он не работает должным образом.
Я не могу объяснить поведение, которое вы наблюдаете с MySQL, демонстрационный код отлично тестирует как MySQL, так и MariaDb. Я попытался разместить его на sqlfiddle, но для создания триггера требуется больше памяти, чем выделено, ошибка MySQL «вне кучи» или что-то в этом роде. Тот же самый точный код отлично работает в моих тестовых средах.
В качестве примера я привел триггер BEFORE UPDATE, который выполняется только тогда, когда он «запускается» оператором UPDATE, изменяющим строку в таблице. Чтобы те же (или похожие) действия выполнялись для INSERT, нам нужно создать триггер BEFORE INSERT.
Вы не можете изменять содержимое таблицы, включенной в запрос, инициировавший триггер; особенно таблица, на которой находится триггер.