Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
更新时相同表上的MySQL触发器_Mysql_Phpmyadmin - Fatal编程技术网

更新时相同表上的MySQL触发器

更新时相同表上的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

我有一张有订单号的桌子。每个事件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
    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
                                 )