【发布时间】:2014-09-26 08:00:00
【问题描述】:
请想象下面描述的两个表格。 这些表(事务编号列)之间存在“关系”,但它们不能符合外键约束,因为它们不是唯一的。
CREATE TABLE COMMAND_DATA
(
TRANSACTIONNUMBER NUMBER(19) NOT NULL,
KEYNAME VARCHAR2(255) NOT NULL,
DATA VARCHAR2(255)
CONSTRAINT PK_COMMAND_DATA PRIMARY KEY (COMMANDTRANSACTIONNUMBER, KEYNAME)
);
CREATE TABLE COMMAND
(
TRANSACTIONNUMBER NUMBER(19) NOT NULL,
COMMANDTYPE NUMBER(10) NOT NULL,
TRANSACTIONTIMESTAMP NUMBER(19) NOT NULL,
SOURCEID VARCHAR2(255),
CONSTRAINT PK_COMMAND PRIMARY KEY (TRANSACTIONNUMBER, COMMANDTYPE)
);
现在,假设在 COMMAND 表中有 10 行包含 transactionnumber = 1,在 COMMAND_DATA 表中有 3 行也包含 transactionnumber = 1。这些数据每次由批处理填充一次。现在我的系统正在处理和删除 COMMAND 表中的行。
我想要实现的是,从 COMMAND 表中删除最后一行 transactionnumber = 1 后,所有具有相同事务号的行都将从表 COMMAND_DATA 中删除。
所以我创建了以下触发器:
CREATE TRIGGER CLEAN_COMMAND_DATA
AFTER DELETE ON COMMAND FOR EACH ROW
DECLARE
pragma autonomous_transaction;
v_count number(10);
BEGIN
select count(*) into v_count from command where TRANSACTIONNUMBER = :old.TRANSACTIONNUMBER;
if v_count = 0 then
delete from COMMAND_DATA where TRANSACTIONNUMBER = :old.TRANSACTIONNUMBER;
end if;
END;
但它不起作用,因为 select 语句也在计算被删除的行数,所以永远不会出现 count(*) 返回零的情况。
如何调整触发器?还是有更好的解决方案?此处无法使用 DELETE ON CASCADE,因为我无法使用 FK...
【问题讨论】:
-
这个看起来很别扭的设计,说明少了点什么。在我看来,它看起来应该有一个 TRANSACTION 表,其 PK 是 TRANSACTIONNUMBER,FK 从 COMMAND 和 COMMAND_DATA 到 TRANSACTION - 然后在完成事务时,从 TRANSACTION 中删除级联到从 COMMAND 和 COMMAND_DATA 中删除。或者 COMMAND_DATA 应该 FK 到 COMMAND - 可能需要 COMMAND 上的合成 PK 以允许这样做。也许 COMMAND.TRANSACTIONNUMBER、TRANSACTIONTIMESTAMP 和可能的 SOURCE_ID 应该在 TRANSACTION 表上,但这当然只是一个猜测。祝你好运。
-
你好 Bob,我明白你的意思,在任何其他情况下我都会同意。但是我稍微简化了这个例子来强调这一点——主键由更多的列组成,数据也包含更多的列(不幸的是一些大的二进制数据)。这个解决方案不是我设计的,但有充分的理由。因此,COMMAND_DATA 中只有一行,而 COMMAND 中至少有数千行。删除的过程(以及实际的业务逻辑)使您无法利用您的想法。这也是我们想做的第一件事——调整设计以更好地适应,但是......
标签: sql oracle triggers constraints