【问题标题】:PLSQL procedure for automatic column type changing用于自动更改列类型的 PLSQL 过程
【发布时间】:2020-09-23 06:51:23
【问题描述】:

假设如下表:

drop table test1;
create table test1(
    A number(10)
);

insert into test1 values (1);
insert into test1 values (10);

如您所见,表 TEST1 已填充。我需要做的是将A列的类型更改为varchar2。由于此列有值,我们不能只使用以下代码:

alter table test1 modify A varchar2(10);

所以我写了存储过程:

  1. 将 A 列重命名为 A1 ->
  2. 然后添加名为 A 的类型为 varchar2 的新列 ->
  3. 然后使用 A1 列中的值更新 A 列 ->
  4. 最终删除旧列 A1。

运行此过程的代码如下:

create or replace procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
is 
v_string clob;
cursor cur is
select column_name
from all_tab_columns 
where table_name = upper(p_tab) and
column_name in (select regexp_substr(p_col,'[^,]+', 1, level) from dual
                 connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
begin
    for i in cur loop
        v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1' || ';';
        dbms_lob.append(v_string,''||chr(10)||'');
        dbms_lob.append(v_string, 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10);');
        dbms_lob.append(v_string,''||chr(10)||'');
        dbms_lob.append(v_string, 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' || ';');
        dbms_lob.append(v_string,''||chr(10)||'');
        dbms_lob.append(v_string, 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' || ';');
        EXECUTE IMMEDIATE v_string;
        DBMS_OUTPUT.PUT_LINE(v_string);
        v_string := NULL;
    end loop;
end;

我正在尝试将此过程应用于 TEST1:

begin
    change_col_type_to_varchar2('TEST1', 'A');
end;

并得到错误:

Error report -
ORA-23290: This operation may not be combined with any other operation
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at "YAVORSKYIY_DM.CHANGE_COL_TYPE_TO_VARCHAR2", line 19
ORA-06512: at line 2
23290. 00000 -  "This operation may not be combined with any other operation"
*Cause:    ALTER TABLE RENAME COLUMN/CONSTRAINT operation was given in
           conjunction with another ALTER TBALE Operation. This is not
           allowed.
*Action:   Ensure that RENAME COLUMN/CONSTRAINT is the only operation
           specified in the ALTER TABLE.

但只需输入:

alter table test1 rename column A to A1;
alter table test1 add A varchar2(100);
update test1 set A = A1;
alter table test1 drop column A1;

完美运行。 有人对如何克服这个问题有任何想法吗?

感谢您的帮助。

【问题讨论】:

  • execute immediate 一次只能执行一项操作。此外,Oracle SQL 没有语句终止符 (;)。

标签: sql oracle plsql


【解决方案1】:

下面会做你所要求的。

declare
    procedure change_col_type_to_varchar2(p_tab in varchar2, p_col in varchar2)
    is 
        v_string clob;
        cursor cur is
        select  column_name
        from    all_tab_columns 
        where   table_name = upper(p_tab) and
                column_name in (select  regexp_substr(p_col,'[^,]+', 1, level) 
                                from    dual
                                connect by regexp_substr(p_col, '[^,]+', 1, level) is not null);
    begin
        for i in cur loop
            v_string := 'alter table ' || p_tab || ' rename column ' || i.column_name || ' to ' || i.column_name || '1';
            execute immediate v_string;
            
            v_string := 'alter table ' || p_tab || ' add ' || i.column_name || ' varchar2(10)';
            execute immediate v_string;
            
            v_string := 'update ' || p_tab || ' set ' || i.column_name || ' = ' || i.column_name || '1' ;
            execute immediate v_string;
            
            v_string := 'alter table ' || p_tab || ' drop column ' || i.column_name || '1' ;
            execute immediate v_string;
            
            v_string := NULL;
        end loop;
       
    end;
begin
        DBMS_OUTPUT.PUT_LINE('Before calling');
        change_col_type_to_varchar2('TEST1','A');
        DBMS_OUTPUT.PUT_LINE('After calling');
end;

【讨论】:

    【解决方案2】:

    好吧,单独执行每个语句,而不是连接它们。而且你不需要 LOB,每个 varchar2 就足够了。

    【讨论】:

    • 我删除了 'v_string' 变量,并为每个命令运行了 4 EXECUTE IMMEDIATE。不幸的是,它不起作用。它会抛出相同的错误消息。
    【解决方案3】:

    我提出了其他算法。

    1. 使用 varchar 列创建新表 'table2';
    2. 从 table1.A 中选择所有值并通过 to_char() 转换插入到 table2;
    3. 删除表1;
    4. 将table2重命名为table1;
    5. 利润!

    【讨论】:

    • 请记住,在旧表上授予的任何对象级权限都需要被捕获并应用于新表。以及所有索引。
    猜你喜欢
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 2017-10-06
    • 1970-01-01
    相关资源
    最近更新 更多