您可以在触发器内刷新物化视图吗?甲骨文 11g

Can you refresh materialised view inside a trigger? Oracle 11g

基本上我有一个实体化视图,当特定的 table、HISTORY_TABLE 更新时需要每月刷新一次,即 HISTORY_TABLE 仅插入到 c 中。每月一次。物化视图不包含与 HISTORY_TABLE 相关的数据,因此我无法在提交时刷新(据我所知)。

据我所读,由于刷新时隐式提交,无法刷新触发器内的 Mview。我有什么想法可以解决这个问题吗?

DROP TRIGGER SYSADM.COMPLETE_NOTIF_SMS;

CREATE OR REPLACE TRIGGER SYSADM.COMPLETE_NOTIF_SMS
AFTER INSERT
ON SYSADM.HISTORY_TABLE
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE

   V_STATUS   NUMBER;
   V_NOTIFICATION_TEXT VARCHAR2(100);
   V_CHECK_CATEGORY VARCHAR2(100);
   
BEGIN
      
      insert into some_table values (v_check_category, v_notification_text,sysdate);  
      -- I want to refresh the Mview/snapshot here 
      DBMS_SNAPSHOT.REFRESH('mview_to_refresh');
                   
EXCEPTION
   WHEN OTHERS
   THEN
      
      -- Some variables are set to send an email.  
   
      RAISE;
END NOTIF_SMS;
/

我不确定我是否做对了,但我使用这样的全局参数刷新我的视图:

  1. 我创建了一个这样的包来设置我想使用的值:

create or replace package dwh.DWH_GLOBAL_PARAMS_MANAGER is

  -- Author  : ALI.FIDANLI
  -- Created : 21.03.2019 10:33:25
  -- Purpose : kelepelik


      PROCEDURE SET_ACC_DATE_CTX(PDATE DATE);


end DWH_GLOBAL_PARAMS_MANAGER;    

CREATE OR REPLACE PACKAGE BODY DWH.DWH_GLOBAL_PARAMS_MANAGER IS
      -- Author  : ALI.FIDANLI
      -- Created : 21.03.2019 10:33:25
      -- Purpose : kelepelik
            PROCEDURE SET_ACC_DATE_CTX(PDATE DATE)
          AS
        BEGIN
            dbms_session.set_context('DWH_PARAMS','REPORT_DATE',TO_CHAR(PDATE,'dd.mm.yyyy'));
            dbms_session.set_context('DWH_PARAMS','REPORT_DATE-1',TO_CHAR(PDATE-1,'dd.mm.yyyy'));
          END;
    END DWH_GLOBAL_PARAMS_MANAGER;

  1. 我在我的视图中使用了这些参数以及所需的参数:

  -- Author  : ALI.FIDANLI
  -- Created : 21.03.2019 10:33:25
  -- Purpose : kelepelik
CREATE OR REPLACE VIEW DWH.V_F_ACCOUNT AS
SELECT TO_DATE (SYS_CONTEXT ('DWH_PARAMS', 'REPORT_DATE-1'),'dd.mm.yyyy')  REPORT_DATE,
                 C.ACC_NO,
                 C.ACC_CURRENCY,
 pkg.func(C.ACC_NO, TO_DATE (SYS_CONTEXT ('DWH_PARAMS', 'REPORT_DATE-1'),'dd.mm.yyyy') ,C.ACC_GL_CODE) ACC_GL_CODE,        
            FROM xxxx.tablename C) ACC

所以我使用

设置日期
begin
  -- Call the procedure
  dwh.dwh_global_params_manager.set_acc_date_ctx(pdate => :pdate);
end;

并使用我的观点....

让我知道它是否适合你,否则我会删除我的回复

对;您不能直接从触发器刷新物化视图,因为您不能在触发器内提交。实际上,您 可以 ,但是触发器必须是一个自主事务,但是 - 不幸的是 - 不会工作,因为它是另一个会话,所以它看不到新添加的行触发触发器的 table。

解决方法可能是

  • 必须提交的存储过程(自主事务)
  • 为什么?因为它将安排一个刷新物化视图的作业,并且 dbms_job.submit 需要提交。因为它 传播 回到调用者(即触发器)并且 - 请记住 - 你不能在触发器内提交,然后过程必须是一个自治事务。
  • 作业将在初始插入后 运行 几分钟,假设您将在此之前提交主事务。

这是一个例子。

您的 some_table、原始 table 内容和物化视图:

SQL> create table some_table (cat varchar2(10), text varchar2(10), datum date);

Table created.

SQL> create materialized view mv_dept as select * from dept;

Materialized view created.

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL>

程序(自主事务,安排刷新物化视图的作业):

SQL> create or replace procedure p_submit as
  2    pragma autonomous_transaction;
  3    i      number;
  4  begin
  5    dbms_job.submit(i,
  6                    'begin DBMS_SNAPSHOT.REFRESH(''mv_dept''); end;',
  7                    sysdate + 1/(24*60),
  8                    'null'
  9                   );
 10    commit;
 11  end;
 12  /

Procedure created.

触发器(调用过程):

SQL> create or replace trigger complete_notif_sms
  2    after insert on dept
  3    for each row
  4  declare
  5    v_status            number;
  6    v_notification_text varchar2(100);
  7    v_check_category    varchar2(100);
  8  begin
  9    insert into some_table values (v_check_category, v_notification_text,sysdate);
 10
 11    -- I want to refresh the Mview/snapshot here
 12    p_submit;
 13  end notif_sms;
 14  /

Trigger created.

SQL>

只是设置日期格式;你不必这样做:

SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';

Session altered.

让我们试一试:将一行插入到 table 中,这是物化视图的来源:

SQL> insert into dept (deptno, dname, loc) values (1, 'a', 'b');

1 row created.

新添加的行在 table ...

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
         1 a              b

...但不在实体化视图中,因为作业尚未开始:

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

职位信息:

SQL> select job, last_date, next_date from user_jobs;

       JOB LAST_DATE           NEXT_DATE
---------- ------------------- -------------------
         8                     12.10.2021 20:34:11

SQL> commit;

Commit complete.

SQL>

一分钟后:

SQL> select sysdate from dual;

SYSDATE
-------------------
12.10.2021 20:36:08

作业已完成;因为这是一次性的工作,所以它从 user_jobs:

消失了
SQL> select job, last_date, next_date from user_jobs;

no rows selected

我们希望物化视图中也有一个新行:

SQL> select * from mv_dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
         1 a              b

SQL>

对了,到了。