pl/sql 触发器完整性约束问题
Posted
技术标签:
【中文标题】pl/sql 触发器完整性约束问题【英文标题】:pl/sql trigger integrity constraint issue 【发布时间】:2012-05-17 20:39:16 【问题描述】:我的任务是创建触发器以在订单表存在时插入到日志表中
-
插入
更新
还在周五下午 5 点到周一上午 9 点之间禁用插入/删除/更新。下面的解决方案涵盖了所有这些,但是因为它是一个前触发器,我不得不关闭完整性约束(这对日志表有影响吗?)
是否有人对我如何能够做到这一点并保持完整性约束(在 logono 列上)有任何建议?
我在考虑 11G 计算触发器,但在之前的答案中建议这不适合使用,加上向后兼容性的问题。
CREATE OR REPLACE TRIGGER log_order
BEFORE INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW
DECLARE out_of_hours EXCEPTION;
BEGIN
IF INSERTING THEN
IF
TO_NUMBER( TO_CHAR( SYSDATE, 'DHH24' ) ) BETWEEN 109 AND 517 THEN
insert into order_log values
(order_log_PK.nextval,
(select user from dual),
:NEW.ono,
(select SYSDATE from dual),
'Order Inserted' ) ;
ELSE
RAISE out_of_hours;
END IF;
END IF;
IF UPDATING THEN
IF
TO_NUMBER( TO_CHAR( SYSDATE, 'DHH24' ) ) BETWEEN 109 AND 517 THEN
insert into order_log values
(order_log_PK.nextval,
(select user from dual),
:NEW.ono,
(select SYSDATE from dual),
'order updated' ) ;
ELSE
RAISE out_of_hours;
END IF;
END IF;
IF DELETING THEN
IF
TO_NUMBER( TO_CHAR( SYSDATE, 'DHH24' ) ) BETWEEN 109 AND 517
THEN
RAISE out_of_hourS;
END IF;
END IF;
EXCEPTION
WHEN out_of_hours THEN
dbms_output.put_line('there is not privelages at this time');
RAISE_APPLICATION_ERROR(-20001, 'CANNOT UPDATE OUT OF HOURS');
END;
谢谢
编辑
完整性问题的出现是因为进入日志表的 :NEW.ono 值尚未插入到订单表中,因为这是一个前触发器,因此违反了 logono 外键。
【问题讨论】:
您需要禁用哪些完整性约束?我不确定我是否遵循了这样做的必要性。 在将 :NEW.ono 插入日志表时,因为它是一个前触发器,所以在 order 表中还没有引用它,所以日志表中的 FK 导致了问题 【参考方案1】:您可以简化触发器,以便只检查周一上午 9 点到周五下午 5 点的条件一次,这样您就只有一个地方可以插入到日志表中,并且无需额外的异常和异常处理程序.
您可以将触发器设置为 AFTER INSERT 触发器,以便在 ORDERS
中已经存在数据之后执行触发器,以便您可以在 ORDER_LOG
中创建一个外键约束,该约束引用 ORDERS
中的 ONO
键.但是,想要创建这种约束似乎很奇怪。如果您将日志表创建为基表的子表,这意味着您将永远无法从ORDERS
中删除一行,因为总会有一个子行,或者您需要删除所有在删除之前,ORDER_LOG
中的行 ONO
。这些通常都不是特别可取的——一般来说,拥有一个日志表的意义在于它将记录所有操作,而不仅仅是对基表中仍然存在的行的操作。
CREATE OR REPLACE TRIGGER log_order
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW
DECLARE
l_operation varchar2(30);
BEGIN
if to_number( to_char( sysdate, 'ddhh24' ) ) between 109 and 517
then
if inserting
then
l_operation := 'Order inserted';
elsif updating
then
l_operation := 'Order updated';
end if;
-- Note that I'm guessing at the names of the columns in order_log
insert into order_log( order_log_pk,
modify_user,
ono,
modify_date,
description )
values( order_log_PK.nextval,
user,
:new.ono,
sysdate,
l_operation );
else
raise_application_error( -20001, 'Cannot update out of hours' );
end if;
END;
虽然在不列出要插入的列的情况下对表执行INSERT
可能在语法上是有效的,但这样做很危险。如果您将来添加另一列,即使不需要,您的 INSERT
也会开始失败。如果您明确列出列,触发器将继续工作。如果您没有明确列出列,则相对难以发现将数据插入错误列的错误。我猜到了列是什么——你必须替换正确的列名。
【讨论】:
很棒的东西。您是否看到在完全独立的触发器中完成日期检查的任何论据? @DylanJackson - 我不会将它放在单独的触发器中,但我会强烈考虑将它放在从触发器调用的单独过程中。我个人不喜欢像这样将日期检查折叠成一行代码,很容易错过一个极端情况。在这种情况下,我宁愿更冗长,因为更容易看到正在发生的事情并在精神上验证它是否按预期工作。例如,书面支票实际上允许在周五下午 5 点到 5:59:59 之间进行更新。 是的,我现在可以看到这一点,你指出来!是时候重新审视我之前的问题了。谢谢。以上是关于pl/sql 触发器完整性约束问题的主要内容,如果未能解决你的问题,请参考以下文章