Триггер MySQL после удаленного обновления не работает

Извините, что снова задаю этот вопрос, так как на форуме так много об этом. но я надеюсь, что моя проблема отличается от других. и извините за мой плохой английский.

Сначала у меня есть 2 таблицы (родительский и дочерний) Родитель (местоположение)

loc_id loc_size 1 100 2 75

Ребенок (область)

ar_id ar_loc_id ar_size 1 2 35 2 2 40

это мой триггер после удаления.

CREATE TRIGGER after_delete_area_location
AFTER DELETE
   ON area FOR EACH ROW

BEGIN

UPDATE location SET loc_size = loc_size + old.ar_size WHERE loc_id=old.ar_loc_id

END;

Например, если я хочу удалить ar_id = '2', тогда ar_size будет обновлен в местоположении loc_size.

поскольку значение loc_size равно «0», то после запуска триггера значение будет равно 40.

проблема в том, что триггер работает неправильно, loc_size вообще не обновляется, просто значение «0» после запуска триггера.

что мне не хватает или что происходит, так как он вообще не работает.

пожалуйста, помогите мне решить эту проблему. Большое спасибо заранее.

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

P.Salmon 19.04.2023 09:28

сделано, обновлено и бросить отвлечение

me.theblackz 19.04.2023 10:20

Опубликованный запрос синтаксически неверен, поскольку в операторе обновления отсутствует терминатор - то, что вам скажет любой ide, и вам может потребоваться установить разделители.

P.Salmon 19.04.2023 11:34

Спасибо @P.Salmon за информацию о разделителях. Но это не проблема в моем запросе. так как он работает хорошо, но нет результата для получения значения из old.ar_size в loc_size

me.theblackz 20.04.2023 07:02
Освоение архитектуры микросервисов с 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
4
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не вижу проблемы в вашем триггере. Я протестировал его, и он работает. Чтобы сделать его полным, я добавил триггер вставки в таблицу area.

create table location(loc_id int,loc_size int);
create table area(ar_id int,ar_loc_id int,ar_size int);


delimiter //

CREATE TRIGGER after_insert_area_location
AFTER insert
   ON area FOR EACH ROW

BEGIN

UPDATE location SET loc_size = loc_size - new.ar_size WHERE loc_id=new.ar_loc_id;

-- Note: In reality, you should throw in an if statement before the UPDATE to make sure there is enough loca_size to be taken away by the ar_size.
END//


CREATE TRIGGER after_delete_area_location
AFTER DELETE
   ON area FOR EACH ROW

BEGIN

UPDATE location SET loc_size = loc_size + old.ar_size WHERE loc_id=old.ar_loc_id;

END//
delimiter ;

insert into location values(1,100),(2,75);

select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |       75 |
+--------+----------+

select * from area;
Empty set (0.00 sec)


-- Test the insert
insert into area values(1,2,35),(2,2,40);
select * from area;
+-------+-----------+---------+
| ar_id | ar_loc_id | ar_size |
+-------+-----------+---------+
|     1 |         2 |      35 |
|     2 |         2 |      40 |
+-------+-----------+---------+

 select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |        0 |
+--------+----------+

-- test the delete
delete from area where ar_id=2;

select * from area;
+-------+-----------+---------+
| ar_id | ar_loc_id | ar_size |
+-------+-----------+---------+
|     1 |         2 |      35 |
+-------+-----------+---------+

select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |       40 |
+--------+----------+


Как видите, как в операциях вставки, так и в операциях удаления значения были обновлены соответствующим образом.
-- ОБНОВЛЕНО ЗДЕСЬ --

Вот усиленная версия триггера after_insert_area_location, в которой я продемонстрирую недавно добавленный оператор IF для сохранения целостности данных. Обратите внимание, что статус SIGNAL используется для создания ошибки, которая служит предупреждением, а также прерывает операцию.

-- First of all, I truncated my table so we can start from scratch.
-- Make sure the original trigger is dropped before creating the newer one to avoid conflicts.

drop trigger after_insert_area_location //
CREATE TRIGGER after_insert_area_location
AFTER insert
   ON area FOR EACH ROW

BEGIN
if (select loc_size from location where loc_id=new.ar_loc_id) - new.ar_size < 0 then
signal sqlstate '77777' set message_text='You cannot take more land than you have'; -- Note: the sqlstate code and the message_text can be modified to your liking
end if;
UPDATE location SET loc_size = loc_size - new.ar_size WHERE loc_id=new.ar_loc_id;

END//

delimiter ;

-- then let's populate the location table:
insert into location values(1,100),(2,75);

select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |       75 |
+--------+----------+

select * from area;
Empty set (0.00 sec)

-- Now we test the insert one row at a time:
 insert into area values(1,2,35);

 select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |       40 |
+--------+----------+

 select * from area;
+-------+-----------+---------+
| ar_id | ar_loc_id | ar_size |
+-------+-----------+---------+
|     1 |         2 |      35 |
+-------+-----------+---------+

-- now we add another row with an ar_size more than its location can afford:

insert into area values(2,2,80);
ERROR 1644 (77777): You cannot take more land than you have

Как видите, оператор SIGNAL в операторе IF триггера вызывает ошибку с кодом SQL_STATE 77777 и сообщением, которые предварительно заданы. Это отменяет изменения, внесенные с момента вставки новой строки.

 select * from location;
+--------+----------+
| loc_id | loc_size |
+--------+----------+
|      1 |      100 |
|      2 |       40 |
+--------+----------+

select * from area;
+-------+-----------+---------+
| ar_id | ar_loc_id | ar_size |
+-------+-----------+---------+
|     1 |         2 |      35 |
+-------+-----------+---------+

Короче говоря, мы можем использовать оператор IF в триггере, чтобы осуществлять некоторый контроль над потоком данных. А оператор SIGNAL можно использовать для преднамеренного вызова ошибки, чтобы остановить/отменить выполнение триггера, а также операцию, которая инициировала триггер. Как указано выше, не только UPDATE в триггере не был выполнен, но и оператор insert, который вызвал триггер, также был отменен.

Спасибо @blabla_bingo, ваш ответ правильный. но для меня это не работает. код также такой же, как вы делаете (вставляете и удаляете), возвращая/обновляя значение в месте, где col loc_size не получил значение из old.ar_size. я не знаю ошибку, так как в журнале нет ошибок, потому что он работает хорошо, ошибок нет вообще. с примечанием, которое Вы мне дали, я этого не делал, потому что я не знаю, что оператор if может работать внутри триггера. Не могли бы Вы помочь мне с запиской, которую Вы упомянули выше. большое спасибо

me.theblackz 20.04.2023 07:00

@me.theblackz Проверьте обновление, сделанное для вас.

blabla_bingo 20.04.2023 08:45

Большое спасибо за оператор if. Никогда не думал, что так можно сделать. большое спасибо за знания. поэтому, если я введу оператор if после удаления, который содержит вот так if (select ar_size from area where ar_loc_id=old.loc_id) = 0 then update location set loc_size=loc_size+old.ar_size where loc_id=old.ar_loc_id endif;, можно ли это сделать так же после удаления? просто проверяя, не равен ли он 0 в ar_size, он должен отправлять значение до нуля. любое предложение по этому поводу?

me.theblackz 20.04.2023 08:59

Я бы учитывал возможность нулей в обоих терминах, объединяя их с 0..

P.Salmon 20.04.2023 09:47

@me.theblackz это утверждение if (select ar_size from area where ar_loc_id=old.loc_id) = 0 then update location set loc_size=loc_size+old.ar_size where loc_id=old.ar_loc_id endif; сбивает с толку, поскольку у вас есть и old.loc_id, и old.ar_size, которые являются взаимоисключающими, поскольку вы можете использовать только ключевые слова old и new для столбцов в сработавшей таблице.

blabla_bingo 20.04.2023 10:39

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

me.theblackz 03.05.2023 13:55

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