CREATE TRIGGER UPDATE_PROFILES_V INSTEAD OF UPDATE ON PROFILES_V REFERENCING NEW AS n OLD AS o FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DECLARE oldmgrid, newmgrid INT; SET oldmgrid = (SELECT empid FROM PROFILES WHERE name = o.mgrname), newmgrid = (SELECT empid FROM PROFILES WHERE name = n.mgrname); IF oldmgrid NOT IN (SELECT empid FROM my_emps) OR newmgrid NOT IN (SELECT empid FROM my_emps) OR o.empid = (SELECT empid FROM PROFILES P WHERE USER = P.sqlid) THEN SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT = 'Not Authorized!'; END IF; UPDATE PROFILES SET empid = n.empid, mgrid = newmgrid, salary = n.salary, sqlid = n.sqlid, name = n.name, ismgr = n.ismgr WHERE empid = o.empid; END$ 最后,下面的 INSTEAD OF 删除触发器保证了用户只能删除其下属,而永远不能删除他们自己。 CREATE TRIGGER DELETE_PROFILES_V INSTEAD OF DELETE ON PROFILES_V REFERENCING OLD AS o FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DECLARE mgrid INT; SET mgrid = (SELECT empid FROM PROFILES WHERE name = o.mgrname); IF mgrid NOT IN (SELECT empid FROM my_emps) OR o.empid = (SELECT empid FROM PROFILES P WHERE USER = P.sqlid) THEN SIGNAL SQLSTATE '70000' SET MESSAGE_TEXT = 'Not Authorized!'; END IF; DELETE FROM PROFILES WHERE empid = o.empid; END$ 完成我们的 DB 模式并将一些初始数据填入表中之后,我们可以查看一切是否正常工作: SELECT * FROM PROFILES_V ORDER BY empid$ EMPID NAME MGRNAME SALARY SQLID ISMGR ----- ------------ ---------- --------- -------- ----- 1 SuperBoss - - sboss Y 1001 BigBoss SuperBoss - bboss Y 1002 MySelf SuperBoss 250000.00 SRIELAU Y 2001 FirstLine BigBoss - fline Y 2002 MiddleMen BigBoss - mmen Y 2003 Yeti MySelf 90000.00 yeti Y 2004 BigFoot MySelf 80000.00 bfoot N 3001 TinyToon FirstLine - ttoon N 3002 Mouse FirstLine - Mouse N 3003 Whatsisname MiddleMen - wname N 3004 Hasnoclue MiddleMen - hclue N 3005 Doesallwork Yeti 15000.00 dwork N 到目前为止,非常顺利。让我们看看 INSTEAD OF 触发器是否象所设计的那样工作。首先我们雇佣 NewGuy 并让他在 Yeti 手下工作: INSERT INTO PROFILES_V VALUES (3006, 'NewGuy', 'Yeti', 35000, 'nguy', 'N')$ SELECT * FROM PROFILES_V WHERE empid = 3006$ EMPID NAME MGRNAME SALARY SQLID ISMGR ----- ------------ ---------- --------- -------- ----- 3006 NewGuy Yeti 35000.00 nguy N 接下来我们把 Doesallwork 提升为 Myself 手下的管理人员并将他的工资提高 30%: UPDATE PROFILES_V SET ismgr = 'Y', salary = salary * 1.30, mgrname = 'MySelf' WHERE name = 'Doesallwork'$ SELECT * FROM PROFILES_V WHERE name = 'Doesallwork'$ EMPID NAME MGRNAME SALARY SQLID ISMGR ----- ------------ ---------- --------- -------- ----- 3005 Doesallwork MySelf 19500.00 dwork Y 为使这个示例保持逼真,Doesallwork 想通了并离开公司: DELETE FROM PROFILES_V WHERE name = 'Doesallwork'$ 到目前为止我们已经有多个视图示例,包括没有表的视图、一张表的视图和外连接中所涉及的一张表的视图。让我们现在研究一下所有表都需要更新的多表连接。 垂直分区数据(即星型连接) 要求对所有的表(同时)进行连接和更新的典型方案是数据的垂直分区。为了简单起见,我们使用 PERSONS 模式。一些 PERSONS 被雇佣,另一些则作为学生招收。有一些 PERSONS 既是雇员又是学生。 CREATE TABLE PERSONS(ssn INT NOT NULL, name VARCHAR(20) NOT NULL)$ CREATE TABLE EMPLOYEES(ssn INT NOT NULL, company VARCHAR(20) NOT NULL, salary DECIMAL(9,2))$ CREATE TABLE STUDENTS(ssn INT NOT NULL, university VARCHAR(20) NOT NULL, major VARCHAR(10))$ 要在应用程序中把所有这些表连接在一起,可能会令人头疼。因此我们创建了一个视图: CREATE VIEW PERSONS_V(ssn, name, company, salary, university, major) AS SELECT P.ssn, name, company, salary, university, major FROM PERSONS P LEFT OUTER JOIN EMPLOYEES E ON P.ssn = E.ssn LEFT OUTER JOIN STUDENTS S ON P.ssn = S.ssn$ 再次声明,这个视图既是不可插入的,也是不可更新或删除的。因此我们需要生成一组完整的 INSTEAD OF 触发器: CREATE TRIGGER INSERT_PERSONS_V INSTEAD OF INSERT ON PERSONS_V REFERENCING NEW AS n FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO PERSONS VALUES (n.ssn, n.name); IF n.university IS NOT NULL THEN INSERT INTO STUDENTS VALUES(n.ssn, n.university, n.major); END IF; IF n.company IS NOT NULL THEN INSERT INTO EMPLOYEES VALUES(n.ssn, n.company, n.salary); END IF; END$ 如果某人与大学相关联,上面的触发器则认为他是一个学生;如果某人与公司相关联,上面的触发器则认为他是一个雇员。 实现 INSTEAD OF DELETE 触发器非常简单。从所有这三张表中删除一个人是很安全的,即使这三张表中没有任何项也是如此: CREATE TRIGGER DELETE_PERSONS_V INSTEAD OF DELETE ON PERSONS_V REFERENCING OLD AS o FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DELETE FROM STUDENTS WHERE ssn = o.ssn; DELETE FROM EMPLOYEES WHERE ssn = o.ssn; DELETE FROM PERSONS WHERE ssn = o.ssn; END$ 现在事情变得有些棘手了。正如定义插入触发器时所表明的那样,学生必须和大学相关联,而雇员必须与公司相关联。因此如果某人获得或失去这些关联之一,那么就需要在相应的表中添加或除去行: CREATE TRIGGER UPDATE_PERSONS_V INSTEAD OF UPDATE ON
上一篇教程: Terry Purcell 谈外连接(第二部分)
下一篇教程: 使用连接的应用程序标识






