Как использовать Case-When и Update в триггере? (Ошибка в моем коде)

Я попытался создать нижеприведенный триггер, но у меня возникла ошибка. Могу ли я использовать «Обновление» или «случай, когда» в триггере? Пожалуйста, помогите мне решить мою проблему здесь.

Пояснение к коду: Я хочу обновить существующую строку после вставки или обновления. Не меняйте «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 27.04.2018 19:56

Раньше у меня был такой же вопрос. Хороший вопрос

user6880933 27.04.2018 19:59

@Uueerdo Итак, что мне делать в этом случае? Есть ли у вас какие-нибудь рекомендации?

user9296546 27.04.2018 20:00

@kiarash Удалось найти какое-нибудь решение?

user9296546 27.04.2018 20:03

@christiano Я нашел глупое и низкопроизводительное решение, я создаю два триггера, один для другой таблицы, и я создаю второй триггер для вставки данных в первую таблицу. Не уверен, есть ли другой способ

user6880933 27.04.2018 20:09

@Christiano вам понадобится несколько запросов вне триггера; это можно сделать на процедурном языке процесса, выполнившего инициируемый вами запрос, или же инициирующий запрос можно заменить хранимой процедурой, которая выполняет этот запрос и любые необходимые последующие запросы.

Uueerdo 27.04.2018 20:11

некоторые примечания: при сравнении равенства символы процента в литерале являются буквальными символами, а не подстановочными знаками, как при сравнении LIKE. То есть 'abc' = '%abc%' оценивается как 0 (ложь), 'abc' LIKE '%abc%' оценивается как 1 (истина). В последнем примере представлена ​​функция MD5, без объяснения причин ее использования.

spencer7593 28.04.2018 15:14
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
7
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У меня была такая же проблема, и я использовал два триггера, Первый триггер отправляет данные в другую таблицу, поэтому теперь вы можете создать еще один триггер для отправки этих данных в первую таблицу. Я думаю, что это низкая производительность, но это единственный способ, которым я ее добился. Я надеюсь, что у других есть другое решение для вас.

Похоже, это могло быть немного нестабильно; просто убедитесь, что второй триггер не запускает повторно первый триггер, иначе вы можете столкнуться с проблемами рекурсии.

Uueerdo 27.04.2018 20:19
Ответ принят как подходящий

Пара замечаний:

Триггер не может выполнить ОБНОВЛЕНИЕ для таблицы, запустившей триггер, это запрещено.

Неквалифицированные ссылки (например, 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

Вау, спасибо большое,

user9296546 27.04.2018 23:27

Я работал над этим и предоставил редакцию в своем вопросе. У меня все еще есть проблема.

user9296546 28.04.2018 00:20

FOLLOWUP добавляется к ответу, предоставляет пример определения триггера, который удовлетворяет спецификации, приведенной в правках к вопросу.

spencer7593 28.04.2018 15:17

добавлено второе продолжение, чтобы ответить на вопрос в заголовке, используя оператор CASE WHEN

spencer7593 28.04.2018 17:07

Большое спасибо за вашу помощь, я очень ценю ваше время. Я буду работать над этим и сделаю это как лучший ответ. Пожалуйста, дайте мне время поработать над этим.

user9296546 02.05.2018 00:05

Осмотрел Trigger, но в fusDates к сожалению ничего не сохраняет.

user9296546 04.05.2018 23:27

@Christiano: Я добавил к ответу ДЕМОНСТРАЦИЯ, чтобы показать, что триггер BEFORE UPDATE выполняет указанные операции.

spencer7593 05.05.2018 05:30

Большое вам спасибо. Кажется, у меня проблема с моим MYSQL, поскольку он не работает должным образом.

user9296546 09.05.2018 02:37

Я не могу объяснить поведение, которое вы наблюдаете с MySQL, демонстрационный код отлично тестирует как MySQL, так и MariaDb. Я попытался разместить его на sqlfiddle, но для создания триггера требуется больше памяти, чем выделено, ошибка MySQL «вне кучи» или что-то в этом роде. Тот же самый точный код отлично работает в моих тестовых средах.

spencer7593 09.05.2018 03:28

В качестве примера я привел триггер BEFORE UPDATE, который выполняется только тогда, когда он «запускается» оператором UPDATE, изменяющим строку в таблице. Чтобы те же (или похожие) действия выполнялись для INSERT, нам нужно создать триггер BEFORE INSERT.

spencer7593 09.05.2018 03:33

Другие вопросы по теме