更新时相同表上的MySQL触发器
我有一张有订单号的桌子。每个事件id的测试(在一个称为订阅的相关表中找到)有一个类似(1,2,3,4,5,…)的序列创建一个好的列表 我想让这个列表在列表编号更改时易于维护(使用phpmyadmin)。 我在更新时触发了表惊吓者更新时相同表上的MySQL触发器,mysql,phpmyadmin,Mysql,Phpmyadmin,我有一张有订单号的桌子。每个事件id的测试(在一个称为订阅的相关表中找到)有一个类似(1,2,3,4,5,…)的序列创建一个好的列表 我想让这个列表在列表编号更改时易于维护(使用phpmyadmin)。 我在更新时触发了表惊吓者 CREATE TRIGGER `edit_startlists` BEFORE UPDATE ON `startlists` FOR EACH ROW BEGIN IF (NEW.order_number != OLD.order_number) THEN
CREATE TRIGGER `edit_startlists` BEFORE UPDATE ON `startlists`
FOR EACH ROW BEGIN
IF (NEW.order_number != OLD.order_number) THEN
IF (NEW.subscription_id!=OLD.subscription_id) THEN
signal sqlstate '45000';
ELSE
IF (NEW.order_number < OLD.order_number) THEN
/*number has become smaller --> everthing equal to or bigger then new , and smaller then old --> +1 */
UPDATE startlists
JOIN subscriptions
ON subscriptions.id = startlists.subscription_id
SET order_number = (order_number+1)
WHERE order_number >= NEW.order_number
AND order_number < OLD.order_number
AND subscriptions.test_of_event_id=(SELECT sub.test_of_event_id FROM subscriptions sub WHERE sub.id=OLD.subscription_id);
ELSE
/*number has become bigger --> everthing equal to or smaller then new , and bigger then old --> -1 */
UPDATE startlists
JOIN subscriptions
ON subscriptions.id = startlists.subscription_id
SET order_number = (order_number-1)
WHERE order_number <= NEW.order_number
AND order_number > OLD.order_number
AND subscriptions.test_of_event_id=(SELECT sub.test_of_event_id FROM subscriptions sub WHERE sub.id=OLD.subscription_id);
END IF;
END IF;
END IF;
END
我正在使用InnoDB,这不是应该只锁定一行吗
我想到了另外一件事:
我在表中添加了一个布尔字段(procedure_check)来进行检查,以避免递归。然后在必要时触发调用该过程的触发器:
DROP TRIGGER IF EXISTS edit_startlist;
DELIMITER $$
CREATE TRIGGER edit_startlist AFTER UPDATE ON startlists
FOR EACH ROW
BEGIN
DECLARE current_test_of_event_id INT;
DECLARE max_order_number INT;
IF (NEW.order_number != OLD.order_number)
THEN
IF (NEW.procedure_edit = 0)
THEN
IF (NEW.subscription_id != OLD.subscription_id)
THEN
SIGNAL SQLSTATE '45000';
ELSE
SET current_test_of_event_id = (SELECT test_of_event_id
FROM (SELECT sub.test_of_event_id
FROM subscriptions sub
WHERE sub.id = OLD.subscription_id
) AS current_subscription
);
SET max_order_number = (SELECT MAX(s.order_number)
FROM startlists s, subscriptions sub
WHERE s.subscription_id = sub.id
AND sub.test_of_event_id = current_test_of_event_id
);
IF (NEW.order_number <= 0 OR NEW.order_number > max_order_number)
THEN
SIGNAL SQLSTATE '45000';
ELSE
CALL adjust_startlist(NEW.order_number,OLD.order_number,current_test_of_event_id);
END IF;
END IF;
ELSE
/*this edit is made by procedure, change the procedure boolean back to 0, so it is ready for a next manual edit*/
UPDATE startlists SET
procedure_edit=0 WHERE
id=NEW.id;
END IF;
END IF;
END$$
DELIMITER ;
我不知道是什么导致了这个错误,更不用说如何解决了。我已经研究过了,但我遇到的所有示例都不适用于此。一般来说,您不能在同一查询中使用正在更新的表。您可以在
from
子句中多次包含该表,但您没有这样做。但是,如果嵌套的查询足够多,则有一个例外
尝试更改此行:
subscriptions.test_of_event_id = (SELECT sub.test_of_event_id
FROM subscriptions sub
WHERE sub.id=OLD.subscription_id
)
致:
MySQL实际上实现了子查询,这使得子查询成为可能。在包括MySQL在内的大多数DBMS中,正如错误所述,您不能在触发器中为同一个表更新表;这是为了避免无限递归(触发器进行更新,然后再次执行触发器,以此类推)。你需要想出不同的逻辑,或者使用一个存储过程。我知道,它确实会导致递归。然而,我真的需要一个简单的方法,因为将有人维护数据库与不太多的IT知识。如何使存储过程在phpmyadmin中易于使用?或者还有其他选择吗?测试过了,但不起作用。我想问题在于更新,而不是像okaram建议的那样选择?可能缺少别名
DELIMITER $$
CREATE PROCEDURE adjust_startlist
(IN new_order_number INT UNSIGNED, IN old_order_number INT UNSIGNED, IN current_test_of_event_id INT UNSIGNED)
MODIFIES SQL DATA
BEGIN
IF (new_order_number < old_order_number)
THEN
/*number has become smaller --> everthing equal to or bigger then new , and smaller then old --> +1 */
UPDATE startlists
JOIN subscriptions
ON subscriptions.id = startlists.subscription_id
SET order_number = (order_number + 1),
procedure_check = 1
WHERE order_number >= new_order_number
AND order_number < old_order_number
AND subscriptions.test_of_event_id = current_test_of_event_id;
/* UPDATE startlists SET order_number = NEW.*/
ELSE
/*number has become bigger --> everthing equal to or smaller then new , and bigger then old --> -1 */
UPDATE startlists
JOIN subscriptions
ON subscriptions.id = startlists.subscription_id
SET order_number = (order_number - 1),
procedure_check = 1
WHERE order_number <= new_order_number
AND order_number > old_order_number
AND subscriptions.test_of_event_id = current_test_of_event_id;
END IF;
END$$
DELIMITER ;
#1415 - Not allowed to return a result set from a trigger
subscriptions.test_of_event_id = (SELECT sub.test_of_event_id
FROM subscriptions sub
WHERE sub.id=OLD.subscription_id
)
subscriptions.test_of_event_id = (SELECT test_of_event_id
FROM (SELECT sub.test_of_event_id
FROM subscriptions sub
WHERE sub.id=OLD.subscription_id
) s
)