我发现很少有问题可以解决同一个问题但没有更好的解决方案。 我需要创建一个Oracle触发器来阻止条件上的新插入,但是要静默(不引发错误)。
Ex:我需要停止插入只有bar ='FOO'的行。 (我无法编辑表的约束,无法访问真正插入的程序等,因此触发器是唯一的选项)
到目前为止,解决方案证实这是不可能的。一个有希望的建议是创建一个中间表,当bar ='FOO'时插入键值,然后在插入完成后从原始表中删除那些记录,这是不正确的。 任何答案都将受到高度赞赏。答案 0 :(得分:0)
显然,在不引发异常的情况下,无法使用触发器来停止插入。
但是,如果您有权访问架构(并询问触发器可能没问题),您可以考虑用视图替换表而不是触发器。
作为当前表格的最小模拟。 myrole
只是表格中授予的特权的一个代表:
CREATE ROLE myrole;
CREATE TABLE mytable (
bar VARCHAR2(30)
);
GRANT ALL ON mytable TO myrole;
现在您重命名该表并确保没有人可以直接访问它,并将其替换为视图。此视图可以通过而不是触发器来保护:
REVOKE ALL ON mytable FROM myrole;
RENAME mytable TO myrealtable;
CREATE OR REPLACE VIEW mytable AS SELECT * FROM myrealtable;
GRANT ALL ON mytable TO myrole;
CREATE OR REPLACE TRIGGER myioftrigger
INSTEAD OF INSERT ON mytable
FOR EACH ROW
BEGIN
IF :new.bar = 'FOO' THEN
NULL;
ELSE
INSERT INTO myrealtable(bar) VALUES (:new.bar);
END IF;
END;
/
所以,如果有人在假视图中插入一个普通行,那么数据会被插入真实表中:
INSERT INTO mytable(bar) VALUES('OK');
1 row inserted.
SELECT * FROM mytable;
OK
但如果有人插入魔法值“FOO”,那么触发器会默默地吞下它并且在真实表中没有任何变化:
INSERT INTO mytable(bar) VALUES('FOO');
1 row inserted.
SELECT * FROM mytable;
OK
警告:如果您还要保护表免受UPDATE的影响,则必须为更新添加第二个触发器。
答案 1 :(得分:0)
一种方法是隐藏行。从12c开始,这很容易:
create table demo
( id integer primary key
, bar varchar2(10) );
-- This adds a hidden column and registers the table for in-database archiving:
alter table demo row archival;
-- Set the hidden column to '1' when BAR='FOO', else '0':
create or replace trigger demo_hide_foo_trg
before insert or update on demo
for each row
begin
if :new.bar = 'FOO' then
:new.ora_archive_state := '1';
else
:new.ora_archive_state := '0';
end if;
end demo_hide_foo_trg;
/
-- Enable in-database archiving for the session
-- (probably you could set this in a log-on trigger):
alter session set row archival visibility = active;
insert into demo (id, bar) values (1, 'ABC');
insert into demo (id, bar) values (2, 'FOO');
insert into demo (id, bar) values (3, 'XYZ');
commit;
select * from demo;
ID BAR
-------- --------
1 ABC
3 XYZ
-- If you want to see all rows (e.g. to delete hidden rows):
alter session set row archival visibility = all;
在早期版本的Oracle中,您可以使用安全策略实现相同的目标。
另一种方法可能是添加一个' required'标志默认为' Y'并将其设置为“N' N' N'在bar = 'FOO'
时触发,并且(假设您无法更改应用程序以使用视图等)有第二个触发器删除所有这些行(或者更好,将它们移动到存档表)。 / p>
create table demo
( id integer primary key
, bar varchar2(10) );
alter table demo add required_yn varchar2(1) default on null 'Y';
create or replace trigger demo_set_not_required_trg
before insert or update on demo
for each row
begin
if :new.bar = 'FOO' then
:new.required_yn := 'N';
end if;
end demo_hide_foo_trg;
/
create or replace trigger demo_delete_not_required_trg
after insert or update on demo
begin
delete demo where required_yn = 'N';
end demo_delete_not_required_trg;
/