我有一个带有订单号的startlists表。每个test_of_event_id(在一个名为subscriptions的相关表中找到),有一个像(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
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
创建触发器没有问题,只有当订单号发生变化时才会出现此错误。
#1442 - Can't update table 'startlists' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
我使用的是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 ;
程序:
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
我不知道是什么导致了这个错误,更不用说如何解决了。我已经对它进行了研究,但我遇到的所有例子都不适用于此。
答案 0 :(得分:1)
通常,您不能在同一查询中使用正在更新的表。您可以在from
子句中多次包含该表,但您不是这样做的。但是,如果您足够嵌套查询,则会有例外。
尝试更改此行:
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
)
MySQL实际上实现了子查询,这使得这允许。