【问题标题】:Synchronizing data in tables in two different schemas in an Oracle database在 Oracle 数据库中同步两种不同模式的表中的数据
【发布时间】:2021-12-30 02:57:45
【问题描述】:

我在一个名为 attendance_database 的 Oracle 架构和另一个名为 payroll_database 的架构中有一个 attendance table,它的表名为 payroll_attendance_table

如果我在attendance_table 中插入新数据然后payroll_attendance_table 与新插入的数据自动同步(自动插入/更新),是否有可能。我听说它可以通过触发器来完成。是这样吗,不然有没有别的办法。我想在数据库端处理这个,不想用任何后端语言来处理。

【问题讨论】:

  • 您应该考虑在这种情况下使用物化视图,而不是触发器。检查这个答案,让您了解dba.stackexchange.com/questions/280854/…
  • 你肯定需要一个触发器。
  • @AnkitBajpai,触发器是一种选择,但可以使用物化视图在提交时快速刷新。
  • @AnkitBajpai 是否有可能从一个数据库触发对其他数据库执行操作的事件,或者触发事件仅适用于同一个数据库
  • 你确定你的意思是“数据库”而不是“模式”吗?您在对另一个答案的评论中说,您在同一台服务器上拥有两个数据库,这意味着您实际上可能有两个不同的模式(Oracle 模式大致相当于大多数其他数据库引擎所称的数据库)。还是这两个 PDB 都在同一个 CDB 中(假设是最新版本的 Oracle)?

标签: sql oracle triggers


【解决方案1】:

首先,由于数据只是在两个不同的模式中,你确定你真的需要将它从一个复制到另一个吗?如果attendance_database.attendance_tablepayroll_database.payroll_attendance_table 应该具有相同的数据,那么删除一个并在payroll_database 中创建一个指向attendance_database 的同义词会更有意义。

grant select on attendance_database.attendance_table
   to payroll_database;

create synonym payroll_database.payroll_attendance_table
   for attendance_database.attendance_table;

如果它们不应该具有相同的数据(例如,payroll_database.payroll_attendance_table 表应该具有其他属性),您很可能希望将 payroll_database.payroll_attendance_table 设为子表。类似的东西

grant references on attendance_database.attendance_table
   to payroll_database;

create table payroll_database.payroll_attendance_table (
  attendance_id integer references attendance_database.attendance_table( attendance_id ),
  <<additional attributes>>
);

如果您真的非常想拥有相同数据的两个单独副本并通过触发器来维护它们,您可以执行类似的操作

create or replace trigger trg_pointless_sync
  before insert or update or delete on attendance_database.attendance_table
  for each row
declare
begin
  if inserting 
  then
    insert into payroll_database.payroll_attendance_table( attendance_id,
                                                           col1,
                                                           col2,
                                                           ...
                                                           colN )
      values( :new.attendance_id,
              :new.col1,
              :new.col2,
              ...,
              :new.colN );
  elsif updating
  then 
    update payroll_database.payroll_attendance_table
       set col1 = :new.col1,
           col2 = :new.col2,
           ...
           colN = :new.colN
     where attendance_id = :new.attendance_id;
  else
    delete from payroll_database.payroll_attendance_table
     where attendance_id = :new.attendance_id;
  end if;
end; 

当然,基于触发器的解决方案通常有些问题。它们可以通过将源表上基于集合的良好、快速的操作转换为递归的逐行操作来施加相当大的性能损失。如果 DBA 想要快速将 attendance_table 恢复到以前的状态,他们可能会产生维护问题,因为有人弄错了一些数据并且没有意识到删除所有数据具有删除所有数据的副作用payroll_database 表。而且它们几乎总是会产生同步问题——例如,如果有人修改了payroll_database 中的某一行会发生什么?或者,如果有人更新了attendance_table 的 PK,我写的触发器不够聪明,无法正确处理(当然,你可以扩展它,但通常这类极端情况比你可能的要多代码),因此这两个表最终将不会完全同步。

【讨论】:

    【解决方案2】:

    要么:

    1. 创建从attendance_databasepayroll_database 的数据库链接。
    2. attendance_database.attendance_tableINSERT 上创建一个行级触发器,跨数据库链接到payroll_database.payroll_attendance_table 的新行。

    或者:

    1. 创建从payroll_databaseattendance_database 的数据库链接。
    2. 通过数据库链接将payroll_attendance_table 创建为MATERIALIZED VIEWFAST REFRESH ON COMMITattendance_database.attendance_table

    【讨论】:

    • @MTO 你能解释一下如何在两个不同的数据库表上创建链接,并尽可能解释触发代码。我在同一台服务器上有两个数据库,有一个专用 IP 地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-28
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    相关资源
    最近更新 更多