2014-10-09 102 views
1

我有一个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 
);$$ 

我遇到的障碍是报名表需要时,它的修改或行被添加到它更新计划表报名。这意味着如果有人登记在节目表上,他们需要在该登记表上登记该动作;如果有人通过注册表注册,则需要在该行所适用的程序表上注册或取消注册。

主要问题是有两种不同的来源是人们从程序中注册的。

就像我说的,错综复杂。我知道这个应用程序的架构不是最好的,但它不是可以改变的。

任何想法都会受到欢迎!请让我知道是否有人有问题或需要澄清。我一直在研究这个问题一段时间,所以我知道我可能会因为对它非常熟悉而将一些东西排除在外。

回答

0

创建更新对方表的触发器没有问题 - 只要触发器不会在无限循环中来回插入即可。

您需要确保由触发器执行的INSERT向另一个表中插入一行,以便而不是产生互惠行为。

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

+0

Karwin先生,非常感谢您抽出时间来回答我的问题。您的意见绝对有帮助! 但是,我有多个表需要与注册表同步,反之亦然。对于注册表,通过这种方法,似乎我必须纠正包含每个表的条件的case语句 - 假设动态SQL不能用于触发器或触发器中使用的存储过程 - 反正有吗?或者如果添加了程序,是否需要硬编码和更新? 感谢您的帮助! – adamjboyce 2014-10-10 13:19:14

+0

对,你不能在触发器中使用动态SQL,因为导致触发器触发的语句本身可能是一个动态SQL语句,并且单个MySQL线程不能有多个动态SQL句柄同时处于活动状态时间。您必须对其进行硬编码并在每次添加新镜像时更新触发器。请记住,如果这看起来太不方便,那可能是您的数据设计需要这种双向镜像可能不是一个好设计的线索。 – 2014-10-10 15:53:48

+0

虽然这是不幸的,但这并不意外。但由于各种因素,它也不适用于我的应用程序。似乎是时候将这种努力从MySQL中解放出来并用PHP开发出来。它不会很优雅,但它应该可以工作(可能每隔几分钟关闭一次cron)。现在我只需说服程序员。 /叹息再次感谢比尔! – adamjboyce 2014-10-10 18:54:48