Как использовать Case-When и Update в Trigger? (Ошибка в моем коде) - PullRequest
0 голосов
/ 27 апреля 2018

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

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

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Пара заметок:

Триггер не может выдать 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

0 голосов
/ 27 апреля 2018

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

...