我有一个触发器,可以通过删除和插入来同时修改表。但是我得到ORA-00001: unique constraint violated
。我认为delete命令实际上没有在插入命令被触发之前提交,因为我不能在触发器中使用commit,所以我不知道如何摆脱该错误。
CREATE OR REPLACE TRIGGER "RESOURCEGROUP_AIU2"
AFTER INSERT OR UPDATE
ON resourcegroup
BEGIN
FOR ROW IN (SELECT *
FROM resourcegroup_moves)
LOOP
IF ROW.oldpath IS NOT NULL
THEN
DELETE FROM mayaccessflat
WHERE resourceGroup <> inheritedFrom
AND resourcegroup = ROW.id
AND inheritedFrom IN (SELECT id
FROM resourcegroup
WHERE ROW.oldpath LIKE path||'/%');
END IF;
INSERT INTO mayaccessflat
(resourcegroup, person, PROFILE, inheritedfrom)
SELECT DISTINCT ROW.ID, ma.person, ma.PROFILE, rg.ID
FROM mayaccess ma, resourcegroup rg
WHERE ma.resourcegroup = rg.ID
AND ma.inherit=1
AND ROW.newpath LIKE rg.PATH || '/%';
END LOOP;
END;
我正在使用Oracle 6 DB。
答案 0 :(得分:1)
问题与提交无关。 INSERT与DELETE在同一事务中发生。因此,问题必须是DELETE不会删除随后的语句正在插入的所有键。
一个原因可能是resourcegroup_moves
中的记录内部不一致。或者它们可能与resourcegroup
中的相关记录不一致。如果是这样,则INSERT会正确触发ORA-00001,并且解决方案将改进对resourcegroup_moves
的验证。
或者,resourcegroup_moves
中记录的集可能是有效的,但是由于您是逐行而不是按组处理这些记录,因此会出现不一致的情况。您对DISTINCT的使用无法解决此问题,因为您没有处理整套设备。如果是这种情况,则可以使用基于集合的方法来解决它:
CREATE OR REPLACE TRIGGER "RESOURCEGROUP_AIU2"
AFTER INSERT OR UPDATE
ON resourcegroup
BEGIN
DELETE FROM mayaccessflat
WHERE resourceGroup <> inheritedFrom
AND (resourcegroup, inheritedFrom) IN
(SELECT rgm.id, rg.id
FROM resourcegroup_moves rgm,
resourcegroup rg
WHERE rgm.oldpath LIKE rg.path||'/%');
INSERT INTO mayaccessflat
(resourcegroup, person, PROFILE, inheritedfrom)
SELECT DISTINCT rgm.ID, ma.person, ma.PROFILE, rg.ID
FROM mayaccess ma
, resourcegroup rg
, resourcegroup_moves rgm
WHERE ma.resourcegroup = rg.ID
AND ma.inherit=1
AND rgm.newpath LIKE rg.PATH || '/%';
END;
将这种业务逻辑放入触发器中并不是一个好习惯。作为存储过程,最好将验证规则应用于resourcegroup
和resourcegroup_moves
。
答案 1 :(得分:0)
您应该将唯一性约束设置为DEFERRABLE
,然后在事务内部使用SET CONSTRAINTS name DEFERRED
来推迟唯一性检查,直到事务提交为止。
请参见Orcale文档中的Specifying Constraint State。