【问题标题】:Alter Table Add Column in PL SQL loop在 PL SQL 循环中更改表添加列
【发布时间】:2015-08-28 20:42:12
【问题描述】:

我正在尝试使用迭代游标的 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;

但我收到一条消息“在此上下文中不允许使用表、视图或序列引用 'Fee_CT'。”不知道我做错了什么。实际数据要大得多,涵盖的时间范围也更广,因此使用多个 alter table 语句是不现实的。加上基础数据会发生变化,所以我需要能够使用基础数据更改列名。

【问题讨论】:

  • 您误用了关系数据库。这些新列应该被规范化,以便月份是表或新表的属性。
  • 我知道它们应该是属性,以及为什么,但在这个特殊问题中,我被要求创建一个交叉表报告。所以是的,我知道这并不理想,但必须解决问题。
  • 通常不需要更改表的结构来生成特定的报告。您似乎解决了错误的问题。
  • 你看过 PIVOT 子句吗?

标签: oracle plsql dynamic-sql


【解决方案1】:

您的表名和列名使用非标准字符 - 小写字母、破折号。这是一个非常糟糕的主意,因为这意味着拥有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 来查看汇编语句。

【讨论】:

    【解决方案2】:

    不知道为什么要动态创建列。但有可能:

    错误:

    1.列名只能有'_'(下划线),不能有其他特殊字符。即,AUG-15 --&gt; AUG_15

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

    2. 应正确使用引号。

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

    【讨论】:

      【解决方案3】:

      始终使用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  -   -   -       -   -
      

      【讨论】:

        猜你喜欢
        • 2017-12-18
        • 2019-04-06
        • 2014-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-13
        相关资源
        最近更新 更多