Как перехватывать ошибки при обновлении вложенных материализованных представлений

#oracle #materialized-views

#Oracle #материализованные представления

Вопрос:

Материализованный вид «MV_AMP»:

 CREATE MATERIALIZED VIEW MV_AMP
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
Select a, b, c from amp;
  

Материализованный вид «MV_BOT», зависящий от «MV_AMP»:

 CREATE MATERIALIZED VIEW MV_BOT
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
SELECT bot.x, bot.y, mv_amp 
FROM bot, mv_amp
WHERE bot.a = mv_amp.a;
  

И создайте уникальный индекс в mv_bot:

 CREATE UNIQUE INDEX mv_bot_idx001 ON mv_bot(x, a);
  

После успешного создания представлений и индекса предположим, что я добавляю повторяющееся значение, которое вызывает ошибку типа (dup_val_on_index) при обновлении mv_bot из-за уникального индекса.

Итак, я выполняю обновление в MV_AMP (главном представлении), используя nested = TRUE, и Oracle не выдал ошибку:

 BEGIN
  dbms_mview.refresh_dependent(number_of_failures => n_failures,
                                   list => 'MV_AMP',
                                   atomic_refresh => TRUE,
                                   nested => TRUE);

EXCEPTION
  WHEN
    OTHERS THEN
        -- it never reach this code
        dbms_output.put_line('Errors: '||SQLERRM);
END;
  

n_failures возвращает: 0 и он никогда не достигает dbms_output внутри исключения.

Мне нужно перехватить ошибку, когда oracle пытается обновить вложенные MVS и войти в таблицу.

Использование Oracle 11g.

Ответ №1:

EXCEPTION Блок достигается только в том случае, если в материализованном представлении есть дублированная строка MV_BOT , что не так.

Вы можете спросить, почему; наиболее вероятный ответ заключается в том, что вам также MV_AMP необходимо обновить материализованное представление, чтобы получить дубликат при объединении ……….. MV_BOT

При чтении документации dbms_mview.refresh_dependent вы понимаете, что вы должны начать с таблицы AMP , чтобы обновить оба MV (начиная с MV_AMP , обновляется только зависимый MV MV_BOT )

Тестовый пример

 create table amp (
a number,
b number,
c number);

create table bot (
a number,
x number,
y number);

CREATE MATERIALIZED VIEW MV_AMP
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
Select a, b, c from amp;

CREATE MATERIALIZED VIEW MV_BOT
  NOLOGGING
  BUILD IMMEDIATE
  REFRESH FORCE
  ON DEMAND
AS
SELECT bot.x, bot.y, mv_amp.a 
FROM bot, mv_amp
WHERE bot.a = mv_amp.a;

CREATE UNIQUE INDEX mv_bot_idx001 ON mv_bot(x, a);

insert into amp(a,b,c) values(1,1,1);
insert into bot(a,x,y) values(1,1,1);
insert into bot(a,x,y) values(1,1,3);
commit;

DECLARE
  n_failures NUMBER;
BEGIN
  dbms_mview.refresh_dependent(number_of_failures => n_failures,
                                   list => 'AMP',
                                   atomic_refresh => TRUE,
                                   nested => TRUE);
   dbms_output.put_line('Failures: '||n_failures);                                                                
EXCEPTION
  WHEN
    OTHERS THEN
        dbms_output.put_line('Errors: '||SQLERRM);
END;
/

--> Errors: ORA-12008: error in materialized view refresh path
--> ORA-00001: unique constraint (xxxxx.MV_BOT_IDX001) violated
  

Комментарии:

1. Возможно, мой пример не совсем объясняет проблему. Пожалуйста, игнорируйте значения, представленные в таблицах примеров, рассмотрите только эти 2 MVS, MV_BOT зависит от MV_AMP. В реальном сценарии в MV_BOT возникает дублированная строка, потому что у нее есть соединения с другими таблицами, которые вызывают это. Если я не начну обновление с «MV_AMP», как я узнал основную таблицу этого представления? В реальном сценарии у него есть выбор из 3 или 4 разных таблиц.

2. @Joel моя точка зрения другими словами — вы обновляете PL / SQL, который только обновляет MV_BOT и сохраняет MV_APP неизменным. Вы должны выбрать некоторый источник MV_APP (здесь APP ) в качестве отправной точки для обновления обоих MVS.

3. Попытался запустить dbms_mview.refresh_dependent с главной таблицей из MV_AMP, но, к сожалению, получил тот же результат. MV_BOT не был обновлен из-за повторяющихся значений в индексе, и процесс обновления не вызвал никакой ошибки.

4. @Joel Я добавил воспроизводимый пример, вызывающий unique constraint исключение. Вы можете попытаться обобщить свой пробег. Обратите также внимание, что в вашем MV_BOT DDL есть синтаксическая ошибка , которую я исправил, используя mv_amp.a вместо mv_amp — надеюсь, это только опечатка.