我正在开发一个代码库,它具有以下类型的模式,用于为表生成代理键。
create or replace
TRIGGER TEST_TRIG
BEFORE INSERT OR UPDATE
ON my_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
BEGIN
IF INSERTING THEN
IF NVL(:NEW.column1, 0) = 0 THEN
SELECT my_table_seq.NEXTVAL
INTO :NEW.column1
FROM dual;
END IF;
END IF;
END;
将此代码称为
的PL / SQL逻辑begin
insert into my_table(0);
end;
我的问题是触发器需要什么? 为什么不做一个,
insert into my_table(my_table_seq.next_val)
并称它为一天? 任何见解都会非常感激。感谢。
答案 0 :(得分:3)
这种特殊模式实际上非常危险,因为它允许某人手动输入可能与已存在的代理键冲突的新ID或您的序列可能在将来生成的ID。
您的触发器应该看起来像这样,以确保每个新记录都获得一个唯一的密钥。如果您使用的是11.2或更高版本,则不需要select ... into ...
CREATE OR REPLACE TRIGGER TEST_TRIG
BEFORE INSERT ON my_table
FOR EACH ROW
BEGIN
:new.column1 := my_table_seq.NEXTVAL;
END;
这种方法的好处是总是完成。无论任何人为这个专栏投入什么价值,都会被覆盖到可行的东西,并使用正确的序列;如果有人忘记在声明中添加它仍然有效。
这使得打破你的代理钥匙成为不可能。
根据你的建议,假设有人放置1而不是;你得到一个主要的密钥违规。如果有人忘了,那么会有更多的错误。您永远不会保证对表的每次更新都通过单个入口点进行,因此触发器可以保证正确填充PK。
值得注意的是,从12c开始,你可以使用identity column,它明确了表和自动增量之间的联系;不需要触发器或序列。表创建DDL的语法是:
create table <table_name> ( <column_name> generated as identity );
答案 1 :(得分:0)
触发器和插入语句都有不同的功能主义者 如果您只想插入数据并且没有为该插入添加日志而不是此插入语句可以正常但您可以确保表中数据的完整性,因为如果可以通过多个源修改它,如果你想要在表上触发的每个insert / update语句的日志,而不管块触发器中的调用是否有用,并且可以在任何时间点检查数据的完整性。