2015-08-28 24 views
1

我正在嘗試使用循環遍歷遊標的循環在表中插入列。該代碼是:Alter Table在PL SQL循環中添加列

declare 
    cursor Months_ET is 
     SELECT distinct to_char(FEE_CD_ACT_SUM_ACCTG_DA, 'MON-YY') as "Month_U" 
     FROM EXPORT_TABLE 
     WHERE EXPORT_TABLE.FEE_CD_ACT_SUM_ACCTG_DA >= to_date('10/01/2013','mm/dd/yyyy') 
     AND EXPORT_TABLE.FEE_CD_ACT_SUM_ACCTG_DA < to_date('10/01/2014', 'mm/dd/yyyy'); 
    n integer := 1; 
begin 
    for mon in Months_ET loop 
     dbms_output.put_line(mon."Month_U"); 
     execute immediate 'Alter table "Fee_CT" add('|| mon."Month_U" ||' varchar(20))'; 
     n := n +1; 
    end loop; 
end; 

在開始光標僅僅指剛得到的唯一月份名稱將DBMS_OUTPUT.PUT_LINE打印出的清單:

SEP-14 
AUG-14 
JUL-14 

所以我知道的變量是不是空的。

因此,使用這些結果我想爲每個月添加三列。但是,我得到一個無效的數據類型錯誤。我也試圖改變for循環來連接這樣的報價之外的表名:

for mon in Months_ET loop 
--Month_List(n) := mon."Month_U"; 
dbms_output.put_line(mon."Month_U"); 
execute immediate 'Alter table' ||"Fee_CT" || 'add('|| mon."Month_U" ||' varchar(20))'; 
n := n +1; 

,但我得到的信息是「表,視圖或序列參考‘Fee_CT’在此背景下允許的。 「不知道我做錯了什麼。實際數據要大得多,涵蓋更廣泛的時間範圍,因此使用多個alter table語句並不現實。加上底層的數據將會發生變化,所以我需要能夠使用底層數據更改列名。

+2

您正在濫用關係數據庫。這些新列應該進行標準化,以便該月是表格的屬性或新表格的屬性。 –

+0

我明白他們應該是屬性,爲什麼,但在這個特定問題中,我被要求創建一個交叉表報告。所以是的,我知道這並不理想,但必須解決問題。 – user2907249

+1

通常不需要更改表結構來生成特定的報表。看來你正在解決錯誤的問題。 – APC

回答

0

不知道爲什麼要創建列dynamically.But有可能,但:

錯誤:

1.列名只能有'_'(下劃線),沒有其他特殊字符。即,AUG-15 --> AUG_15

  • 當使用別名以用於進一步處理使用SUBQUERY(Month_U)

  • 行情應適當使用。

  • 執行語句中關鍵字/變量之間的空格。
  • create table Table_A 
    (id integer, 
    date1 date 
    ); 
    -- Table created. 
    
    begin 
        insert into table_A values (1,trunc(sysdate)); 
        insert into table_A values (2,trunc(sysdate+100)); 
    end; 
    
    select to_char(date1, 'MON-YY') as "Month_U" from table_A; 
    --AUG-15 
    --DEC-15 
    
    Declare 
        cursor months_ET is select month_u from 
          (select to_char(date1, 'MON_YY') AS Month_U from table_A) DUAL; 
        sql_stmnt varchar2(400) ; 
        table_name varchar2(20) := 'Table_A'; 
        column_name varchar2(20) := 'New_col1'; 
        data_type varchar2(20) := 'date' ; -- you can change to varchar2 
    Begin 
        FOR MON in months_ET 
        LOOP 
        sql_stmnt := ' alter table ' || table_name || ' add(' || MON.MONTH_U 
        || ' ' || data_type || ') ' ; 
        dbms_output.put_line(sql_stmnt); 
        Execute immediate sql_stmnt ; 
        END LOOP; 
    End; 
    

    OUTPUT:

    alter table Table_A add(AUG_15 date) 
    alter table Table_A add(DEC_15 date) 
    
    Table altered. 
    

    enter image description here

    0

    始終使用DBMS_OUTPUT.PUT_LINE來測試您的execute immediate聲明。

    • 給出關鍵字/變量之間的空間。
    • 使用單引號

    立即檢查該實例:

    create table Table_A(id integer); 
    -- Table created. 
    
    Declare 
        sql_stmnt varchar2(400) ; 
        table_name varchar2(20) := 'Table_A'; 
        column_name varchar2(20) := 'New_col1'; 
        data_type varchar2(20) := 'varchar2(20)' ; 
    Begin 
        sql_stmnt := ' alter table ' || table_name || ' add(' || Column_name || ' ' || data_type || ') ' ; 
        execute immediate sql_stmnt ; 
        dbms_output.put_line(sql_stmnt); 
    End; 
    
    -- alter table Table_A add(New_col1 varchar2(20)) 
    -- Table altered. 
    
    Desc Table_A; 
    
        Column Data Type Length Precision Scale 
        ID  NUMBER  22 - 0 - - - 
        NEW_COL1 VARCHAR2 20 - - -  - - 
    
    2

    你的表名和列名使用非標準的字符 - 小寫字母,連字符。這是一個非常糟糕的主意,因爲這意味着有to wrap every reference in double-quotes。每當必須修復PLS-00357ORA-00903ORA-00904異常時,每個必須使用架構的人都會詛咒您,因爲他們忘記了用雙引號標識符。你看,它甚至抓住你了:)

    但如果你真的要堅持,你需要的語句是:

    execute immediate 'Alter table "Fee_CT" add("'|| mon."Month_U" ||"' varchar(20))'; 
    

    表名是樣板文本的一部分而不是一個變量。您需要使用雙引號包裝非標準列名稱。確保樣板在關鍵字周圍有空格。

    最重要的是,請記住,動態SQL中的語法錯誤會引發運行時錯誤,而不是編譯錯誤。使用日誌記錄或DBMS_OUTPUT來查看彙編語句。