【问题标题】:How to create a trigger the triggers a self-referencing trigger...yeah如何创建触发器触发器自引用触发器......是的
【发布时间】:2014-12-04 15:44:26
【问题描述】:

我有一个 MySQL 数据库,它具有...有趣的架构和复杂的注册过程。有几个程序表在更新、插入或删除时需要在历史登记表上插入行。我已经在每个表(大约 30 个不同的表)上使用触发器,使用以下迭代所有表:

DROP TRIGGER IF EXISTS programTable_afterinsert;$$
CREATE TRIGGER programTable_afterinsert AFTER INSERT ON programTable
FOR EACH ROW
    BEGIN
        IF NEW.Enrolled = 1
            THEN
                INSERT INTO enrollment (ID, Action, Date_Updated, User, Program, Reason, Action_Date)
                    VALUES (NEW.ID, 'Enrolled', NOW(), 'programUser', 'programName', 'Enrolled in program', NOW());
        ELSEIF NEW.Enrolled = 0
            THEN
                INSERT INTO enrollment (Member_ID, Action, Date_Updated, User, Program, Reason, Action_Date)
                    VALUES (NEW.ID, 'Disenrolled', NOW(), 'programUser', 'programName', 'Disenrolled from program', NOW());
        END IF;
    END;$$

DROP TRIGGER IF EXISTS programTable_afterupdate;$$
CREATE TRIGGER programTable_afterupdate AFTER UPDATE ON programTable
FOR EACH ROW
    BEGIN
        IF NEW.Enrolled = 1
            THEN 
                INSERT INTO enrollment (ID, Action, Date_Updated, User, Program, Reason, Action_Date)
                    VALUES (NEW.Member_ID, 'Enrolled', NOW(), 'programUser', 'programName', 'Enrolled in program', NOW());
        ELSEIF NEW.Enrolled = 0
            THEN 
                INSERT INTO enrollment (ID, Action, Date_Updated, User, Program, Reason, Action_Date)
                    VALUES (NEW.ID, 'Disenrolled', NOW(), 'programUser', 'programName', 'Disenrolled from program', NOW());
        END IF;
    END;$$

DROP TRIGGER IF EXISTS programTable_afterdelete;$$
CREATE TRIGGER programTable_afterdelete AFTER DELETE ON programTable
FOR EACH ROW
    BEGIN
        IF OLD.Enrolled = 1
            THEN 
                INSERT INTO enrollment (ID, Action, Date_Updated, User, Program, Reason, Action_Date)
                    VALUES (OLD.ID, 'Disenrolled', NOW(), 'programUser', 'programName', 'Removed from program', NOW());
        END IF;
    END;$$

可以使用以下内容创建精简版的注册和计划表:

delimiter $$

CREATE TABLE `programTable1` (
  `ID` varchar(15) NOT NULL,
  `Enrolled` tinyint(3) unsigned NOT NULL,
  `Referral_Date` datetime NOT NULL,
  `Referral_Source` varchar(255)
);$$

CREATE TABLE `programTable2` (
  `ID` varchar(15) NOT NULL,
  `Enrolled` tinyint(3) unsigned NOT NULL,
  `Referral_Date` datetime NOT NULL,
  `Referral_Source` varchar(255)
);$$

CREATE TABLE `enrollment` (
  `ID` varchar(15) NOT NULL,
  `Action` varchar(12) NOT NULL,
  `Date_Updated` timestamp NOT NULL,
  `User` varchar(12) default NULL,
  `Program` varchar(25) NOT NULL,
  `Notes` varchar(100) default NULL,
  `Reason` varchar(45) default NULL,
  `Action_Date` datetime NOT NULL
);$$

我遇到的障碍是注册表需要在修改或添加一行时更新程序表的注册。这意味着如果有人在程序表上注册,他们需要在注册表上有一个条目以执行该操作;如果某人通过登记表登记,则需要在该行适用的程序表上将他们更新为登记或取消登记。

主要问题是人们从两个不同的来源注册该计划。

就像我说的,令人费解。我知道这个应用程序的架构不是最好的,但它不是可以改变的。

欢迎任何想法!请让我知道是否有人有问题或是否需要任何澄清。我已经为此工作了一段时间,所以我知道由于对它非常熟悉,我可能会遗漏一些东西。

【问题讨论】:

    标签: mysql stored-procedures dynamic triggers


    【解决方案1】:

    创建更新彼此表的触发器没有问题——只要触发器不继续在无限循环中来回插入。

    您需要确保触发器执行的 INSERT 将行插入到另一个表中不会导致交互操作。

    我在最近的另一个问题中写了一个例子:Mirror tables: triggers, deadlock and implicit commits

    【讨论】:

    • 先生。卡尔文,非常感谢您花时间回答我的问题。您的意见绝对有帮助!但是,我有多个表需要与注册表同步,反之亦然。对于注册表,通过这种方法,我似乎必须纠正一个包含每个表条件的 case 语句 - 假设动态 SQL 不能用于触发器或触发器中使用的存储过程- 周围有吗?或者如果添加了程序,这一切都需要硬编码和更新吗?感谢您的帮助!
    • 对,你不能在触发器中使用动态SQL,因为触发触发器的语句可能是动态SQL语句本身,单个MySQL线程不能有多个动态 SQL 句柄同时处于活动状态。每次将新表添加到镜像时,您都必须对其进行硬编码并更新触发器。请记住,如果这看起来太不方便了,那可能表明您需要这种双向镜像的数据设计可能不是一个好的设计。
    • 虽然很不幸,但这并不意外。但由于多种因素,它也不是我的应用程序的选择。似乎是时候将这项工作从 MySQL 中抽出来并用 PHP 开发了。它不会很优雅,但它应该可以工作(可能每隔几分钟就关闭 cron)。现在我只需要说服程序员。 /sigh 再次感谢比尔!
    猜你喜欢
    • 1970-01-01
    • 2014-02-02
    • 2012-07-30
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多