如何绕过唯一约束违规?
Posted
技术标签:
【中文标题】如何绕过唯一约束违规?【英文标题】:How to get around a unique constraint violation? 【发布时间】:2021-10-10 08:26:24 【问题描述】:我有一个问题,我无法实现的自治事务将尝试将数据插入表中,但数据可能已经存在。我们需要找到一种解决方案来处理唯一完整性约束,而不需要移除约束,因为另一个程序依赖于这个约束验证。
我尝试创建一个删除现有条目的前触发器,但这似乎不起作用。
CREATE OR REPLACE TRIGGER TG_BEFORE_INSERT_REPLACE_DC_DEVICE_TACTICAL_FIX_INV_LOADER
BEFORE INSERT
ON DC_DEVICE
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
FAKE_DEVICE_STATUS VARCHAR2(3 BYTE);
BEGIN
-- constraint exception occurs before this statement
DELETE FROM DC_DEVICE WHERE DEVICE_ID_PK = :NEW.DEVICE_ID_PK;
END;
在那之后,我想到了删除约束并添加带有条件语句的触发器,来自损坏程序的所有条目都是不同的,所以我可以区分它们。使用该语句,如果设备已经存在并且插入不是来自损坏的程序,则无法继续,否则删除现有条目并继续插入。
上面的解决方案似乎是一个可行的解决方案,但我的问题是,是否有任何功能可以让我以更优雅的方式做同样的事情?
【问题讨论】:
这似乎是应用程序插入数据的问题,它应该使用合并或处理违反唯一约束。无论如何,一个想法是重命名表并在其前面放置一个视图,然后您可以添加而不是触发器将违规行放入异常表中。 您想对您尝试插入的违反约束的记录做什么?你想保留它们,你想替换现有的? 我想替换记录,但我无法更改应用程序的查询,我们无法控制代码,但我们必须找到解决方案... 您如何区分这些记录?您可能希望使用基于函数的索引来创建条件唯一约束。 如果设备状态 != 'FKE' 那么 device_id 应该是唯一的吗?如果是这样,您可以使用基于函数的索引来实现。 【参考方案1】:一种选择是使用instead of
触发器。但是,此解决方案要求您重命名表并使用它们的名称创建视图。这样您不会影响应用程序逻辑,但它可能会影响整体性能,因此应正确测试。
不过,使用触发器来更改错误的应用程序逻辑并不是一个好主意。我理解您的困境,即有时我们需要找到解决现有问题的方法,但这并不能解决问题。
无论如何,下面是一个您可以应用于您的逻辑的简单示例
SQL> create table t ( c1 number primary key , c2 varchar2(1) ) ;
Table created.
SQL> alter table t rename to tbl_t ;
Table altered.
SQL> create view t as ( select c1 , c2 from tbl_t ) ;
View created.
现在我们创建一个instead of
触发器
SQL> create or replace trigger tr_v_t
2 instead of insert
3 on t
4 for each row
5 declare
6 pk_violation_exception exception;
7 pragma exception_init(pk_violation_exception, -00001);
8 begin
9 insert into tbl_t (c1,c2)
10 values ( :new.c1,:new.c2 );
11 exception
12 when pk_violation_exception then
13 dbms_output.put_line('ora-00001 (pk_violation_exception) captured');
14 update tbl_t
15 set c2 = :new.c2
16 where c1 = :new.c1 ;
17* end;
SQL> /
Trigger created.
使用此触发器,任何违反约束的尝试都会使最终表中的值更新成为可能。
SQL> select * from t ;
no rows selected
SQL> insert into t values ( 1 , 'A' ) ;
1 row created.
SQL> commit ;
Commit complete.
SQL> insert into t values ( 2, 'B' ) ;
1 row created.
SQL> commit ;
Commit complete.
SQL> insert into t values ( 2, 'C' ) ;
ORA-00001 (pk_violation_exception) captured
1 row created.
SQL> select * from tbl_t ;
C1 C
---------- -
1 A
2 C
【讨论】:
我 100% 同意您的说法,但我无能为力,感谢您的回答,我会尝试并在成功后将其作为官方答案 这在我的情况下并不完全有效,但它是一个非常好的选择,谢谢!以上是关于如何绕过唯一约束违规?的主要内容,如果未能解决你的问题,请参考以下文章
在 Hibernate 中使用 SEQUENCE 时导致唯一约束违规的原因是啥?