在PL SQL循环中更改表添加列

时间:2015-08-28 20:42:13

标签: oracle plsql dynamic-sql

我正在尝试使用遍历游标的for循环在表中插入列。代码是:

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;

jsut开头的光标获取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;

但我收到的消息是&#34;表,查看或序列参考&#39; Fee_CT&#39;在这种情况下不允许。&#34;不确定我做错了什么。实际数据要大得多,并且涵盖更广泛的时间范围,因此使用多个alter table语句并不现实。加上底层数据将会发生变化,因此我需要能够使用基础数据更改列名。

3 个答案:

答案 0 :(得分: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查看汇编的语句。

答案 1 :(得分: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 :(得分:0)

不确定为什么要动态创建列。但是有可能:

  

错误:

     

1.Column名称只能有&#39; _&#39;(下划线),没有其他特殊字符。即。AUG-15 --> AUG_15

     
      
  1. 使用别名进行进一步处理时使用SUBQUERY(Month_U)

  2.   
  3. 报价应该正确使用。

  4.   
  5. 执行语句中关键字/变量之间的空格。
  6.   
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;

<强>输出:

 alter table Table_A add( AUG_15 date ) 
 alter table Table_A add( DEC_15 date ) 

Table altered.

enter image description here