TRIGGER не может выполнять операции DML над таблицами, на которые есть ссылки в операторе запуска.Это ограничение описано в справочном руководстве по MySQL.
Другими словами: тело триггера UPDATE ON product
не может выдать оператор UPDATE
для таблицы product
.
Это одна из ошибок в определении триггера.
Помимо этого, есть некоторые проблемы с синтаксисом.За FOR EACH ROW
должно следовать ключевое слово BEGIN
(исключение составляет триггер, являющийся одним оператором.)
Оператор IF
должен быть закрыт с END IF
(не просто * 1016).*)
Но мы должны переосмыслить весь подход, а не просто исправить синтаксис.
Давайте разберемся, чего мы пытаемся достичь, может быть, в качестве примера.
Допустим, у нас есть таблица product
id mfr input_qty shelf_qty
-- --- --------- ---------
1 fee 3 39
2 fi 0 7
Каково будет ожидаемое состояние таблицы после того, как мы выпустим эти операторы:
UPDATE product SET mfr = 'fo' WHERE id = 1 ;
UPDATE product SET input_qty = 4 WHERE id = 2 ;
То естьМы можем предсказать результат этих заявлений, если не сработали триггеры.Но как триггеры должны влиять на поведение, изменять результаты этих утверждений?Что нам нужно для триггера (ов)?
UPDATE product SET input_qty = 5 , shelf_quantity = 11 WHERE id = 1;
Мы не можем написать код, чтобы сделать что-то, если у нас нет спецификации;нам нужно иметь несколько тестов, которые мы можем использовать, чтобы убедиться, что код, который мы пишем, выполняет то, что должен делать.В противном случае мы просто применяем синтаксис SQL, надеясь, что все как-нибудь сработает.
Чего мы пытаемся достичь?
Если мы хотим «увеличить» shelf_qty
по некоторому предоставленному значению нормативный шаблон будет выглядеть примерно так (без триггера):
UPDATE product t
SET t.shelf_qty = t.shelf_qty + 1
WHERE t.id = 1 ;
Мы ссылаемся на текущее значение столбца shelf_qty
, добавляем к нему 1, а затем присваиваем этот новыйзначение обратно в столбец shelf_qty
.
Обновление 1
Выражение можно использовать после ключевого слова THEN
в выражении CASE
.Допускается операция добавления в выражении.
Синтаксис, показанный для «собранного запроса sql» (действителен; мы надеемся, что перед END
стоит ELSE qty, поскольку он немного странный(не незаконно, просто необычно) выполнить UPDATE
без предложения WHERE
(чтобы обновить каждую строку в таблице).
Синтаксис выглядит корректным, но я не могу проверить семантику, например* являются ли sku
и qty
действительными ссылками на столбцы и т. д.)
Лично я бы сделал операцию UPDATE (добавлена к вопросу) следующим образом:
UPDATE product t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'fee' THEN 1
WHEN 'fi' THEN 2
ELSE 0
END
Но я не совсем уверен, что мы должны назначить qty
, когда sku
не указан.Я предполагаю, что мы оставим значения qty
в этих строках без изменений.Я просто не понимаю преимущества триггера для этого варианта использования,
Обновление 2
"Насколько я знаю, операциипосле THEN запрещены " [в выражении CASE]
Это зависит от того, что подразумевается под операциями .Синтаксис для выражения CASE:
CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ... ELSE expr5 END
или:
CASE expr1 WHEN expr2 THEN expr3 WHEN expr4 THEN expr5 ... ELSE expr6 END
Где exprN
- выражения.В выражении может использоваться операция сложения.
Мы могли бы написать обновление следующим образом:
UPDATE products t
SET t.qty = CASE
WHEN t.sku = 'foo' THEN t.qty + 1
WHEN t.sku = 'bar' THEN t.qty + 2
ELSE t.qty
END
WHERE t.sku IN ('foo','bar')
Но мы могли бы облегчить будущему читателю распознавание наших намерений, выразив еговот так
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN 'foo' THEN 1
WHEN 'bar' THEN 2
ELSE 0
END
WHERE t.sku IN ('foo','bar')
Обобщение довольно простое.Текст SQL, сгенерированный приложением с использованием именованных заполнителей, будет выглядеть примерно так:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN :sku1 THEN :qty1
WHEN :sku2 THEN :qty2
WHEN :sku3 THEN :qty3
ELSE 0
END
WHERE t.sku IN ( :wsku1 , :wsku2 , :wsku3 )
или с использованием позиционных заполнителей, например:
UPDATE products t
SET t.qty = t.qty
+ CASE t.sku
WHEN ? THEN ?
WHEN ? THEN ?
WHEN ? THEN ?
ELSE 0
END
WHERE t.sku IN ( ? , ? , ? )
Мы можем видеть, как будет выглядеть оператординамически расширяется для переменного числа {sku:qty}
комбинаций
продолжение
Это все не рекомендуется использовать TRIGGER.Это не лучший способ справиться с требованием.Но, чтобы ответить на вопрос, который был задан ...
Если нам нужно использовать триггер, задайте:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 41
4 fum 0 11
и
UPDATE product t
SET t.input_qty = CASE t.sku
WHEN 'fo' THEN 1
WHEN 'fum' THEN 2
ELSE 0
END
WHERE t.sku IN ('fo','fum')
затем с этим определенным триггером:
DELIMITER $$
CREATE TRIGGER product_bu
BEFORE UPDATE ON product
FOR EACH ROW
BEGIN
IF NEW.input_qty > 0 THEN
-- add provided value of input_qty to shelf_qty
SET NEW.shelf_qty = HEW.shelf_qty + NEW.input_qty;
-- set input_qty to zero
SET NEW.input_qty = 0;
END IF;
END$$
Ожидаемый результат будет:
product
id sku input_qty shelf_qty
-- --- --------- ---------
3 fo 0 42
4 fum 0 13
Но мне не имеет смысла делать это с триггером.Я не вижу выгоды.Просто кажется, что это излишне и запутанно изменяет нормальное поведение UPDATE
.