2013-06-05 92 views
1

我設計了一個將視圖中的數據複製到oracle相應表中的過程。我所做的只是調用傳遞'視圖名稱'作爲參數的過程,並創建相應的表(如果不存在,則刪除並創建表)。所以這是動態發生的,我有大約50個視圖,並且它們被安排爲oracle作業。不允許使用零長度的列 - 從視圖中創建表

現在即將發佈,我有幾個表並在某些天以下錯誤而失敗......

ORA-01723:零長度列不允許

我知道這樣做的原因是視圖中的幾列是空的,但不是所有的日子。是的,我應該爲這些列使用CAST,但正如我所提到的,這種情況是動態發生的,我不知道那些列是哪一列或哪些視圖是這樣的?任何導致在我開始創建表之前確定是否存在「零長度列」,以便我可以考慮一些解決方案。任何更好的補救措施,真的很感激。

注:

  1. CREATE TABLE TABLE_NAME AS SELECT * FROM VIEW_NAME - >這是我的表創建SQL。
  2. 我選擇這個的原因是'INSERT INTO'由於記錄和鎖定可能需要更多的時間和資源。

感謝, 納加」

+0

爲什麼不使用物化視圖?你完全需要這些表格嗎? – tbone

+0

視圖是簡單過濾從單個表中選擇的,還是將函數應用於值? –

回答

1

正如你說你調用一個過程,從視圖中創建一個表。因此,我假設您已經在使用動態SQL(原生動態SQL,也稱爲EXECUTE IMMEDIATE語句或DBMS_SQL包)來執行DDL語句。然後,您可以使用Oracle字典視圖(例如USER_VIEWSUSER_TAB_COLUMNS)生成更復雜的CREATE TABLE AS語句,以獲取有關列的類型,長度,比例以及編寫正確CAST調用所需的任何其他信息。

髒例子如下:

create or replace view v 
as 
    select decode(dummy, 'Y', '123') s 
     , 1 n 
     , 2.2 f 
     , cast (1.1 as number(5,3)) fs 
    from dual 
/

set serveroutput on 
declare 
    l_query varchar2(32767) := 'create table t as select <column list> from v'; 
    l_type varchar2(100); 
begin 
    for tc in (
    select * from user_tab_columns 
    where table_name = 'V' 
    order by column_id 
) loop 
    l_type := tc.data_type; 
    l_type := l_type || 
     case tc.data_type 
     when 'NUMBER' then 
      case when tc.data_precision is not null then '(' || tc.data_precision || case when tc.data_scale is not null then ','||tc.data_scale end || ')' end 
     when 'VARCHAR2' then 
      '(' || tc.char_length || ' ' || case tc.char_used when 'C' then 'char' else 'byte' end || ')' 
     end; 
    l_query := replace(l_query, '<column list>', 'cast("'||tc.column_name||'" as '|| l_type ||') "'||tc.column_name||'" ,<column list>'); 
    end loop; 
    l_query := replace(l_query, ',<column list>'); 

    dbms_output.put_line(l_query); 
end; 
/

結果:

view V created. 
anonymous block completed 
create table t as select cast("S" as VARCHAR2(3 char)),cast("N" as NUMBER),cast("F" as NUMBER),cast("FS" as NUMBER(5,3)) from v 

好運。

+0

很好的答案。我認爲使用數據字典是做這件事的正確方法。但是示例代碼僅適用於原始數據類型,並且需要在類似'timestamp'的情況下進行擴展,並在任何其他情況下重現類型名稱。 – ThinkJet

+0

超級謝謝你。我嘗試了這樣的東西,它的工作原理...創建視圖dummy_view爲 選擇1作爲id,null作爲dept_no,'naga'作爲雙名稱; 創建表dummy_table作爲 SELECT * FROM dummy_view UNION ALL 選擇流延(null作爲數),澆鑄(null作爲VARCHAR2(10)),流延從雙(null作爲VARCHAR2(10)),其中1 = 2 – Naga

+0

中當然,代碼必須擴展,這只是一個例子來展示這個想法。 – suPPLer

0

我選擇這個的原因是'INSERT INTO'由於記錄和鎖定可能需要更多的時間和資源。

我認爲你已經基於你的方法來丟棄和重新創建表,每次錯誤的信念。截斷它們,並使用直接路徑插入(可選地使用nologging),在沒有此問題的情況下可以得到幾乎相同的結果。如果您正在使用:

create table .. as select from ... 

...然後您完全記錄操作。