【发布时间】:2016-09-04 06:16:23
【问题描述】:
我正在编写一个实际用途的数据库,目前涉及一些触发器和约束。
在删除指定的行之前,我的一个触发器必须将列值设置为 0,但删除不能与...的约束一起工作,所以我决定 BEFORE DELETE 在更新列值之后删除约束从另一个表中,我将使用我的第二个触发器再次ADD。
但是我可以让它工作:
ALTER TABLE teams ADD CONSTRAINT teams_to_trainer FOREIGN KEY (coda)
REFERENCES trainer(coda);
--insert values
--...
--Procedure in which I execute the alter table commands
CREATE OR REPLACE PROCEDURE constraint_operation (p_hardcod IN VARCHAR2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
resource_busy EXCEPTION;
PRAGMA EXCEPTION_INIT(resource_busy,-54);
BEGIN
EXECUTE IMMEDIATE p_hardcod;
EXCEPTION
WHEN resource_busy
THEN
DBMS_LOCK.SLEEP(5);
COMMIT;
END;
/
--My Two Triggers
CREATE OR REPLACE TRIGGER delete_trainer
BEFORE DELETE
ON trainer
FOR EACH ROW
BEGIN
constraint_operation('ALTER TABLE teams DROP CONSTRAINT teams_to_trainer');
UPDATE teams SET coda = 0 WHERE :old.coda = coda;
END;
/
CREATE OR REPLACE TRIGGER delete_trainer_add_constraint
AFTER DELETE
ON trainer
FOR EACH ROW
BEGIN
constraint_operation('ALTER TABLE teams ADD CONSTRAINT teams_to_trainer
FOREIGN KEY (coda)REFERENCES trainer(coda)');
END;
/
当调用时:
DELETE FROM trainer WHERE coda = 14;
我明白了:
SQL 错误:ORA-02291:完整性约束 (USER.TEAMS_TO_TRAINER) 违反 - 未找到父键 02291. 00000 - “违反完整性约束 (%s.%s) - 未找到父键” *原因:外键值没有匹配的主键值。 *操作:删除外键或添加匹配的主键。
我似乎找不到问题,我认为调用该过程将消除约束。
我做错了什么?
谢谢。
【问题讨论】:
-
如果您必须禁用约束才能使 DML 工作,那么您的设计存在严重问题,您应该重新考虑。
-
您可以禁用约束并减少流失,但整个想法需要重新考虑。当您的代码在行忙时休眠,您只需推迟完成交易。这不会扩展。用表格描述告诉我们您需要做什么。
-
为什么不完全放弃约束,并在
before insert触发检查外键是否存在,否则引发异常。 -
问题是我不想引发异常,因为在我的设计中删除该行是正常行为。所以我试图删除一个教练,就像足球队的教练一样。然后我更新那个教练所在团队的价值,这就是为什么我需要一个外键在教练。但是创建约束会使培训师变成一个孩子。我想删除培训师,但我希望团队保持静止。
-
为什么你用零(没有匹配的教练,因此错误)而不是 null 来更新,以表明没有与团队相关的教练?这似乎比必须添加一个虚拟教练更安全。您甚至不需要触发器,只需设置约束
on delete set null。
标签: oracle plsql oracle-sqldeveloper