Sql oracle中的突变触发器问题

Sql oracle中的突变触发器问题,sql,oracle,plsql,oracle11g,Sql,Oracle,Plsql,Oracle11g,我面临着变异的触发错误 我将在这里描述这个问题 我使用的是表格A和表格B TableA包含一个名为empChecked的列,该列可以包含两个值'-','+'。 TableB包含一个名为mgrChecked的列,该列可以包含两个值'-','+' 当前要求empChecked和mgrchecked中的两个字段必须同步。我的意思是,如果empChecked更新为“+”,那么表B中的mgr checked必须更新为“+”,反之亦然。这两个字段都可以从前端进行更新 我在两个表上都创建了触发器。但我面临着o

我面临着变异的触发错误

我将在这里描述这个问题 我使用的是表格A和表格B

TableA包含一个名为empChecked的列,该列可以包含两个值'-','+'。 TableB包含一个名为mgrChecked的列,该列可以包含两个值'-','+'

当前要求empChecked和mgrchecked中的两个字段必须同步。我的意思是,如果empChecked更新为“+”,那么表B中的mgr checked必须更新为“+”,反之亦然。这两个字段都可以从前端进行更新

我在两个表上都创建了触发器。但我面临着ora-04091错误


请向我推荐实现这一点的方法?

您对细节有点不清楚,但我认为这将有助于假设您在两个表上都有一个ID列

CREATE TRIGGER tri_table_a
    AFTER UPDATE ON table_a
DECLARE
    hits NUMBER :=0;
BEGIN
    SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
    IF hits>0 THEN
        UPDATE table_b b SET mgr_checked=(SELECT emp_checked FROM table_a a WHERE a.id=b.id);
    END IF;
END;
/

CREATE TRIGGER tri_table_b
    AFTER UPDATE ON table_b
DECLARE
    hits NUMBER :=0;
BEGIN
    SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
    IF hits>0 THEN
        UPDATE table_a a SET emp_checked=(SELECT mgr_checked FROM table_b b WHERE a.id=b.id);
    END IF;
END;
/
关键是不要对每一行使用,这将导致表锁定

编辑

这不会与表锁或ORA-04091冲突,因为触发器条件a.k.a.中的每一行都没有行触发器,这意味着只有在整个更新操作完成后才会执行触发器主体

这不会导致无限循环,因为当触发器体中的count*返回0时,触发器体内的更新将不会执行

此外,必须使用count*,因为这是一个语句触发器,没有:new.emp_checked available

一般场景:更新表\u a->触发tri\u表\u a->[触发]检查计数->[触发]更新表\u b->触发tri\u表\u b->[触发]检查计数->完成

在发布这个答案之前,我自己也试过了


您对细节有点不清楚,但我认为这将有助于假设两个表上都有一个ID列

CREATE TRIGGER tri_table_a
    AFTER UPDATE ON table_a
DECLARE
    hits NUMBER :=0;
BEGIN
    SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
    IF hits>0 THEN
        UPDATE table_b b SET mgr_checked=(SELECT emp_checked FROM table_a a WHERE a.id=b.id);
    END IF;
END;
/

CREATE TRIGGER tri_table_b
    AFTER UPDATE ON table_b
DECLARE
    hits NUMBER :=0;
BEGIN
    SELECT count(*) INTO hits FROM table_a a INNER JOIN table_b b ON (a.id=b.id) WHERE a.emp_checked<>b.mgr_checked;
    IF hits>0 THEN
        UPDATE table_a a SET emp_checked=(SELECT mgr_checked FROM table_b b WHERE a.id=b.id);
    END IF;
END;
/
关键是不要对每一行使用,这将导致表锁定

编辑

这不会与表锁或ORA-04091冲突,因为触发器条件a.k.a.中的每一行都没有行触发器,这意味着只有在整个更新操作完成后才会执行触发器主体

这不会导致无限循环,因为当触发器体中的count*返回0时,触发器体内的更新将不会执行

此外,必须使用count*,因为这是一个语句触发器,没有:new.emp_checked available

一般场景:更新表\u a->触发tri\u表\u a->[触发]检查计数->[触发]更新表\u b->触发tri\u表\u b->[触发]检查计数->完成

在发布这个答案之前,我自己也试过了


与其使用触发器进行这种同步,不如创建一个视图 将包含来自TableB的所有数据的命名TableB not mgrchecked+来自TableA的empChecked列 像这样的

create or replace view TAbleB as
  select t1.id
       , t1.Column2
       , ... 
       , t1.ColumnN
       , t.empChecked
    from TableA t
       , TableB t1
   where t.id = t1.id

与其使用触发器进行这种同步,不如创建一个视图 将包含来自TableB的所有数据的命名TableB not mgrchecked+来自TableA的empChecked列 像这样的

create or replace view TAbleB as
  select t1.id
       , t1.Column2
       , ... 
       , t1.ColumnN
       , t.empChecked
    from TableA t
       , TableB t1
   where t.id = t1.id

变异表错误是一种代码味道。它几乎总是指向一个糟糕的数据模型,通常没有足够的标准化

当然,这里有一个糟糕的数据模型。表中有一列具有两个设置。那很好。现在,您需要将同一列添加到第二个表中,并使这两个列保持同步。这个新专栏完全没有意义。该新列中没有查询第一个表无法获得的信息


这就是ORA-04091告诉你的。你可以花很多时间构建一个变通方法,但这一切都是徒劳的

变异表错误是一种代码味道。它几乎总是指向一个糟糕的数据模型,通常没有足够的标准化

当然,这里有一个糟糕的数据模型。表中有一列具有两个设置。那很好。现在,您需要将同一列添加到第二个表中,并使这两个列保持同步。这个新专栏完全没有意义。该新列中没有查询第一个表无法获得的信息


这就是ORA-04091告诉你的。你可以花很多时间构建一个变通方法,但这一切都是徒劳的

删除其中一列,因为它们显然表示相同的信息。否则将导致无限循环。为什么不把它移到域层,在一个事务中更新两个表呢?@vicdor,我无法访问业务逻辑,因为一个已经存在了。另一个是我创造的。因此,我不能触摸这些表列,请删除其中一列,因为它们显然代表相同的信息。否则将导致无限循环。为什么不把它移到域层,在一个事务中更新两个表呢?@vicdor,我无法访问业务逻辑,因为一个已经存在了。另一个是我创造的。因此,我无法触摸这些表列您正在更新此表中的表,这将导致锁定。你是艾尔
因此,从正在触发的表中选择。。。“这是最初的问题,与锁无关。”Ben在我尝试后发了帖子。在oracle中,当表锁被释放时,触发器将在整个操作insert、update等完成后执行。这就是为什么我不能使用:new.checked和stuff,并且必须选择count来检查是否需要更新。@Ben Two。尽管有开发者这个名字,但对于这个星球上的某个人来说,并不是所有的东西都是理想的可访问的。我知道这是一个丑陋的解决方案,但这并不意味着没有人应该知道它。我曾经不得不构建触发器和视图,甚至虚拟行,以适应其他人创建的表定义,而我无法更改这些定义。在此更新表时,将导致锁定。您还将从正在触发的表中选择。。。“这是最初的问题,与锁无关。”Ben在我尝试后发了帖子。在oracle中,当表锁被释放时,触发器将在整个操作insert、update等完成后执行。这就是为什么我不能使用:new.checked和stuff,并且必须选择count来检查是否需要更新。@Ben Two。尽管有开发者这个名字,但对于这个星球上的某个人来说,并不是所有的东西都是理想的可访问的。我知道这是一个丑陋的解决方案,但这并不意味着没有人应该知道它。我曾经不得不构建触发器和视图,甚至虚拟行,以适应其他人创建的、我无法更改的表定义。我不会把这件事告诉我的老板为什么这个项目需要两个小时的应急工作。我们的场景是不同的,一个插入的行,然后另一个触发器查询同一个表,所以我们创建一个包来保存需要插入的行,并在行触发器完成后插入它。有人说这会起作用..代码气味-我喜欢它。我不会把这件事告诉我的老板为什么这个项目需要两个小时的应急工作。我们的场景是不同的,一个插入的行,然后另一个触发器查询同一个表,所以我们创建一个包来保存需要插入的行,并在行触发器完成后插入它。有人说这会起作用。。