Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Помогите в написание триггера / 15 сообщений из 15, страница 1 из 1
30.08.2018, 07:31
    #39695285
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Здравствуйте, требуется помощь в написании триггера.
Задача: Есть две таблицы [сообщения] и [история_сообщений], на инсерт в таблицу [сообщения] поставил триггер.
Который следит чтобы при достижении 100 записей в диалоге сообщения переходили в архив. Возможно написано не самым умным способом но работает и ладно.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
DELIMITER $$
CREATE TRIGGER count_and_insert BEFORE INSERT ON messages
FOR EACH ROW 
BEGIN
SET @CNT =  (SELECT count(*) FROM messages WHERE hash = NEW.hash);
	IF @CNT > 100 THEN
		INSERT INTO history_chats (id_table_messages,idchat, iduser,`text`,`hash`,message_sended,message_delivered,date_create,`delete`)
		SELECT * FROM (SELECT * FROM `messages` WHERE `hash` = NEW.hash ORDER BY id DESC LIMIT 1) t  ORDER BY t.id;
	END IF;
END$$
DELIMITER ;


Второй половиной задачи является очистка сообщений из таблицы [сообщения] после того как они попали в архив.
Мне показалось логичным, что он должен отрабатывать после вставки сообщений [история_сообщений] и выглядит вот так.
Код: sql
1.
2.
3.
4.
5.
6.
7.
DELIMITER $$
CREATE TRIGGER delete_messages AFTER INSERT ON history_chats
FOR EACH ROW 
BEGIN
		DELETE FROM messages WHERE id = NEW.id_table_messages;
END$$
DELIMITER ;


Но у MySQL свое мнение на этот счет, и он мне сообщает, что таблицу [сообщения] модифицировать нельзя, так как она участвует в другом процессе.
Дословно вот что говорит: Can't update table 'tbl' in stored function/trigger because it is already used by statement which invoked this stored function/trigger
...
Рейтинг: 0 / 0
30.08.2018, 07:32
    #39695286
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-name,)) Собственно вопрос в том, как обойти это ограничение.
...
Рейтинг: 0 / 0
30.08.2018, 07:37
    #39695289
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Обойти ограничение нельзя.

Есть на выбор как миниум три различных подхода к решению задачи.

Первый - вместо удаления создание в триггере EVENT на удаление записи.

Второй - реализация логики в виде не запроса, а хранимой процедуры.

Третий - ротация. Т.е. сразу создаётся 100 пустых записей, и вместо вставки новой записи и удаления старой выполняется обновление самой старой записи.
...
Рейтинг: 0 / 0
30.08.2018, 07:55
    #39695295
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Akina,

Ага, спасибо, я признаться и сам думал про хранимую процедуру, только не понимаю в какой момент ее вызывать?
...
Рейтинг: 0 / 0
30.08.2018, 08:32
    #39695310
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Вопрос немного офтопный, пытаюсь создать процедуру
Код: sql
1.
2.
3.
4.
5.
6.
DELIMITER ||;
	BEGIN
    CREATE PROCEDURE delete_messages(IN id INT)
    DELETE FROM messages WHERE id =  id;
	END ||
DELIMITER ;


MySQL не создает но и не ругается, это что может быть? Права рутовые.
...
Рейтинг: 0 / 0
30.08.2018, 08:54
    #39695319
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-name,

А такой вариант создался 0_0
Код: sql
1.
2.
3.
4.
5.
6.
7.
delimiter //
CREATE PROCEDURE deletemessages (IN id INT)
     BEGIN
       SET SQL_SAFE_UPDATES = 0;
       DELETE FROM messages WHERE id =  id;
    END//
delimiter ;
...
Рейтинг: 0 / 0
30.08.2018, 10:16
    #39695368
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-nameне понимаю в какой момент ее вызывать?Вместо INSERT INTO messages ... делаете CALL insert_into_messages(...).
Nick-name
Код: sql
1.
WHERE id =  id

Самому не смешно? Это же WHERE true...
Крайне опасное занятие - называть переменные так же, как имена полей.
...
Рейтинг: 0 / 0
30.08.2018, 11:07
    #39695396
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Один фик, не сработало, то же самое пишет.
...
Рейтинг: 0 / 0
30.08.2018, 11:23
    #39695408
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-name , приводите полный порядок своих действий (какой именно код создан, как именно запущен) и точные цитаты сообщений.
И - Вы не забыли удалить ранее созданные триггеры?
...
Рейтинг: 0 / 0
30.08.2018, 11:57
    #39695433
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Нет, удалить не забыл.
Вот перечень всего того что создано и как происходит
1. Триггер на создание сообщения. Проверяет если больше 5 сообщений то делаем запись самого первого в архивную таблицу.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
-- DROP TRIGGER count_and_insert;
DELIMITER $$
CREATE TRIGGER count_and_insert BEFORE INSERT ON messages
FOR EACH ROW 
BEGIN
SET @CNT =  (SELECT count(*) FROM messages WHERE hash = NEW.hash);
    IF @CNT > 5 THEN
            INSERT INTO history_chats (id_table_messages,idchat, iduser,`text`,`hash`,message_sended,message_delivered,date_create,`delete`)
	    SELECT * FROM (SELECT * FROM `messages` WHERE `hash` = NEW.hash ORDER BY id DESC LIMIT 1) t  ORDER BY t.id;
    END IF;
END$$
DELIMITER ;



2. Триггер на вставку в архивную таблицу, вызывает хранимую процедуру
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
-- DROP TRIGGER delete_messages;
DELIMITER $$
CREATE TRIGGER delete_messages AFTER INSERT ON history_chats
FOR EACH ROW 
BEGIN
		  CALL deletemessages(NEW.id_table_messages);
END$$
DELIMITER ;



3. и наконец сама процедура
Код: sql
1.
2.
3.
4.
5.
6.
7.
-- DROP PROCEDURE deletemessages;
delimiter //
CREATE PROCEDURE deletemessages (IN id_message INT)
     BEGIN
            DELETE FROM messages WHERE id = id_message;
     END//
delimiter ;


Результат:
Error Code: 1442. Can't update table 'messages' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

Вроде ничего не забыл.
...
Рейтинг: 0 / 0
30.08.2018, 12:26
    #39695457
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-nameТриггер на создание сообщения. Проверяет если больше 5 сообщений то делаем запись самого первого в архивную таблицу.Ошибка. BEFORE INSERT проверяет намерение, а не факт вставки записи - т.е. если при вставке будет ошибка, и запись не вставится, триггер всё одно уже отработал. Операцию такого рода надо выполнять в триггере AFTER INSERT - т.е. когда запись уже реально вставлена в таблицу.

Дополнительно - зачем нужна промежуточная переменная @cnt? можно же сразу
Код: sql
1.
2.
3.
IF (SELECT count(*) 
    FROM messages 
    WHERE hash = NEW.hash) > 5 THEN


Nick-nameТриггер на вставку в архивную таблицу, вызывает хранимую процедуру
Ошибка. Процедура должна вызываться ВМЕСТО запроса на вставку в messages, а не в триггере.

ИТОГО и суммарно:

Вместо
INSERT INTO messages -> trigger (INSERT INTO history_chats) -> DELETE FROM messages
выполняется просто
CALL insert_into_messages (данные для вставки)
А вот внутри её уже и выполняется всё вышеперечисленное:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
CREATE PROCEDURE insert_into_messages (IN параметры_для_вставки)
INSERT INTO messages (поля_для_вставки) VALUES (параметры_для_вставки);
IF (SELECT COUNT(*) FROM messages) > 5 THEN
    INSERT INTO history_chats (список_полей)
        SELECT список_полей
        FROM messages 
        ORDER BY id DESC
        LIMIT 5,4294967295;
    DELETE messages.* 
        FROM messages 
        INNER JOIN history_chats 
            ON messages.id = history_chats.id;
END IF;
END;


Дополнительно: в процедуре следует сформировать хэндлер(ы) на случай ошибки на любой стадии, саму ошибку фиксировать (где и что) и возвращать в OUT-параметре(ах), который потом можно проанализировать и понять, что выполнено, а что нет.
...
Рейтинг: 0 / 0
30.08.2018, 13:40
    #39695519
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
То есть все должно выглядеть так - триггер срабатывает по AFTER INSERT
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
 DROP TRIGGER count_and_insert;

DELIMITER $$
CREATE TRIGGER count_and_insert AFTER INSERT ON messages
FOR EACH ROW 
BEGIN
		CALL insert_into_messages (NEW.idchat,NEW.iduser,NEW.text,NEW.hash,NEW.message_sended,NEW.message_delivered);
END$$
DELIMITER ;


А процедура выглядит так
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
DROP PROCEDURE insert_into_messages;
delimiter //
CREATE PROCEDURE insert_into_messages (IN chat INT, user INT,message TEXT,m_hash varchar(255),m_s INT,m_d INT)
     BEGIN
      INSERT INTO messages (idchat,iduser,`text`,`hash`,message_sended,message_delivered) values (chat, user,message,m_hash,m_s,m_d);
    IF (SELECT COUNT(*) FROM messages WHERE `hash` = m_hash) > 5 THEN
		INSERT INTO history_chats (id_table_messages,idchat, iduser,`text`,`hash`,message_sended,message_delivered,date_create,`delete`)
	    SELECT * FROM (SELECT * FROM `messages` WHERE `hash` = m_hash  ORDER BY id DESC LIMIT 1) t  ORDER BY t.id;
		DELETE messages.* 
			FROM messages 
			INNER JOIN history_chats 
				ON messages.id = history_chats.id;
	END IF;
     END//
delimiter ;


Если да то это не помогло ошибка та же (((
и на BEFORE INSERT то же
...
Рейтинг: 0 / 0
30.08.2018, 13:46
    #39695525
Melkij
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-name,

то есть триггера у вас вообще быть не должно.
вместо insert в таблицу делаете процедуру. А не из триггера вызываете процедуру.
...
Рейтинг: 0 / 0
30.08.2018, 15:18
    #39695635
Nick-name
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Melkij,
Спасибо большое, все работает
...
Рейтинг: 0 / 0
30.08.2018, 15:46
    #39695659
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите в написание триггера
Nick-nameТо есть все должно выглядеть так - триггер срабатывает по AFTER INSERTТриггера вообще быть не должно.
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Помогите в написание триггера / 15 сообщений из 15, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]