2014-01-15 53 views
3

我們有一些偏好使用物化視圖的環境,但常規應用程序使用常規視圖。爲了使事情更容易,我們希望我們的應用程序能夠根據配置參數以自動方式自動將所有常規視圖遷移到物化視圖。將視圖腳本轉換爲物化視圖(Oracle)

我已經寫了我認爲最需要這個腳本工作的東西,但是我在最後的碰觸中掙扎着。可能還有一些我需要解決的逃避問題。

現在,腳本創建一個名爲'magic'的視圖,然後嘗試轉換該視圖,但目前爲止它不能轉換到物化視圖階段。我不確定我做錯了什麼。任何幫助不勝感激。

我看到的錯誤如下。

Error report: 
ORA-00911: invalid character 
ORA-06512: at line 49 
ORA-00911: invalid character 
00911. 00000 - "invalid character" 
*Cause: identifiers may not start with any ASCII character other than 
      letters and numbers. $#_ are also allowed after the first 
      character. Identifiers enclosed by doublequotes may contain 
      any character other than a doublequote. Alternative quotes 
      (q'#...#') cannot use spaces, tabs, or carriage returns as 
      delimiters. For all other contexts, consult the SQL Language 
      Reference Manual. 
*Action: 
Attempting to drop materialized view named MAGIC 
No materialized view found with name MAGIC 
Attempting to drop view named MAGIC 
Success. 
Attempting to create materialized view named MAGIC 
    CREATE MATERIALIZED VIEW "MYDB"."MAGIC" ("MAGIC") AS 
    SELECT 'MAGIC' FROM DUAL; 

Failed to create materialized view, recreating original view MAGIC 
ERROR: Could not recreate view named MAGIC. 
SQL was: 
    CREATE OR REPLACE FORCE VIEW "MYDB"."MAGIC" ("MAGIC") AS 
    SELECT 'MAGIC' FROM DUAL; 

PL/SQL代碼如下。

clear; 
SET serveroutput ON size 1000000; 
/** 
* Converts all views in the database to materialized views. 
*/ 

CREATE OR REPLACE VIEW "MAGIC" ("MAGIC") AS SELECT 'MAGIC' FROM DUAL; 

BEGIN 
    FOR cur_rec IN (SELECT object_name, object_type FROM user_objects WHERE object_type='VIEW' and object_name='MAGIC') 
    LOOP 
    BEGIN 
     FOR cur_view IN 
     (SELECT TRIM(REPLACE(REPLACE(DBMS_METADATA.GET_DDL('VIEW', cur_rec.object_name), 'CREATE OR REPLACE FORCE VIEW', 'CREATE MATERIALIZED VIEW'), 'CREATE OR REPLACE VIEW', 'CREATE MATERIALIZED VIEW')) "MATERIALIZED_VIEW", 
     TRIM(DBMS_METADATA.GET_DDL('VIEW', cur_rec.object_name)) "VIEW" 
     FROM DUAL 
    ) 
     LOOP 
     BEGIN 
      BEGIN 
      DBMS_OUTPUT.PUT_LINE('Attempting to drop materialized view named ' || cur_rec.object_name); 
      EXECUTE IMMEDIATE 'drop materialized view ' || cur_rec.object_name; 
      DBMS_OUTPUT.PUT_LINE('Success.'); 
      EXCEPTION 
      WHEN OTHERS THEN 
      DBMS_OUTPUT.PUT_LINE('No materialized view found with name ' || cur_rec.object_name); 
      IF SQLCODE != -12003 THEN 
       RAISE; 
      END IF; 
      END; 
      BEGIN 
      DBMS_OUTPUT.PUT_LINE('Attempting to drop view named ' || cur_rec.object_name); 
      EXECUTE IMMEDIATE 'drop view ' || cur_rec.object_name; 
      DBMS_OUTPUT.PUT_LINE('Success.'); 
      EXCEPTION 
      WHEN OTHERS THEN 
      DBMS_OUTPUT.PUT_LINE('No view found with name ' || cur_rec.object_name); 
      IF SQLCODE != -942 THEN 
       RAISE; 
      END IF; 
      END; 
      -- create the view as a materialized view. 
      BEGIN 
      DBMS_OUTPUT.PUT_LINE('Attempting to create materialized view named ' || cur_rec.object_name); 
      DBMS_OUTPUT.PUT_LINE(cur_view."MATERIALIZED_VIEW"); 
      EXECUTE IMMEDIATE cur_view."MATERIALIZED_VIEW"; 
      DBMS_OUTPUT.PUT_LINE('Success.'); 
      EXCEPTION 
      WHEN OTHERS THEN 
      BEGIN 
       DBMS_OUTPUT.PUT_LINE('Failed to create materialized view, recreating original view ' || cur_rec.object_name); 
       EXECUTE IMMEDIATE cur_view."VIEW"; 
      EXCEPTION 
      WHEN OTHERS THEN 
       DBMS_OUTPUT.PUT_LINE('ERROR: Could not recreate view named ' || cur_rec.object_name || '.'); 
       DBMS_OUTPUT.PUT_LINE('SQL was:' || cur_view."VIEW"); 
       RAISE; 
      END; 
      END; 
     END; 
     END LOOP; 
    END; 
    END LOOP; 
END; 

回答

3

的問題是它試圖執行SQL:

CREATE MATERIALIZED VIEW "MYDB"."MAGIC" ("MAGIC") AS 
SELECT 'MAGIC' FROM DUAL; 

動態SQL應該是一個單一的聲明,不能有一個語句終止/分離器;這是最後的;它不喜歡。

您可以通過添加到您的塊set_transform_param() procedure呼叫停止dbms_metadata包括它的DDL擺在首位,你叫get_ddl()前:

dbms_metadata.set_transform_param(dbms_metadata.session_transform, 
    'SQLTERMINATOR', false); 
+0

太棒了,非常感謝! – mrswadge

0

更新 - 最終解決

運行這個腳本時,數據庫崩潰了,因爲我的一些視圖依賴於其他視圖。我感覺這是以多線程的方式完成的,並且導致服務器崩潰並且隨着視圖處於各種準備狀態而被刻錄。從順序處理的角度來看,我看不到這可能會失敗。依賴視圖既可以作爲物化視圖,也可以作爲常規視圖存在。

最後,有可能這些時間可能會減少,這些是我工作的價值,但在撰寫此答案時我沒有測試過較低的閾值。

set serveroutput on size 1000000; 
/** 
* Converts all views in the database to materialized views. 
*/ 
begin 
    dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'SQLTERMINATOR', false); 
    for cur_rec in (SELECT object_name, object_type from user_objects where object_type='VIEW') 
    loop 
    begin 
     for cur_view in 
     (select trim(replace(replace(dbms_metadata.get_ddl('VIEW', cur_rec.object_name), 'CREATE OR REPLACE FORCE VIEW', 'CREATE MATERIALIZED VIEW'), 'CREATE OR REPLACE VIEW', 'CREATE MATERIALIZED VIEW')) "MATERIALIZED_VIEW", 
     trim(dbms_metadata.get_ddl('VIEW', cur_rec.object_name)) "VIEW" 
     from dual) 
     loop 
     begin 
      begin 
      execute immediate 'drop materialized view ' || cur_rec.object_name; 
      dbms_lock.sleep(5); 
      exception 
      when others then 
      if sqlcode != -12003 then 
       raise; 
      end if; 
      end; 
      begin 
      execute immediate 'drop view ' || cur_rec.object_name; 
      dbms_lock.sleep(5); 
      exception 
      when others then 
      if sqlcode != -942 then 
       raise; 
      end if; 
      end; 
      -- create the view as a materialized view. 
      begin 
      dbms_output.put_line('Attempting to create materialized view named ' || cur_rec.object_name); 
      execute immediate cur_view."MATERIALIZED_VIEW"; 
      dbms_lock.sleep(5); 
      exception 
      when others then 
      begin 
       dbms_output.put_line('Failed to create materialized view, recreating original view ' || cur_rec.object_name); 
       dbms_output.put_line('Error was: ' || sqlerrm(sqlcode)); 
       dbms_output.put_line(cur_view."MATERIALIZED_VIEW"); 
       execute immediate cur_view."VIEW"; 
       dbms_lock.sleep(5); 
      exception 
      when others then 
       dbms_output.put_line('ERROR: Could not recreate view named ' || cur_rec.object_name || '.'); 
       dbms_output.put_line('SQL was:' || cur_view."VIEW"); 
       raise; 
      end; 
      end; 
     end; 
     end loop; 
    end; 
    end loop; 
end;