ORA-00911:使用execute immediate执行无效字符

时间:2014-09-26 10:05:12

标签: oracle

下面的代码用于动态创建partititon。我面临错误无效的chararcter错误。在执行消息输出时,我没有遇到任何错误。请帮我解决这个问题。

create or replace package        shs_pk_dyn_par is
        procedure dynamic_proc ( p_table_name in varchar2,p_month_from in number,p_month_to in number,p_status out varchar2 , p_messgae out varchar2 );
end;

create or replace package body shs_pk_dyn_par is

procedure dynamic_proc ( p_table_name in varchar2,p_month_from in number,p_month_to in number,p_status out varchar2 , p_messgae out varchar2 ) is

v_sql           varchar2(4000);
v_month_from    number;
v_month_to      number;
v_append        number;
v_year          number;
v_p_year        number;
v_p_check       number;
begin

        p_status := 'S';
        p_messgae := 'Success';

        v_month_from := 0; v_month_to := 0;v_sql :=null;v_append:=null;v_year:=null;v_p_year:=null;
        v_p_check := null;

        v_month_from := substr(p_month_from,5,6 );
        v_month_to   := substr(p_month_to,5,6 );
        v_year       := substr(p_month_to,1,4 );
        ---v_sql := ' ALTER TABLE '||p_table_name||' ADD';

        for i in v_month_from..v_month_to
        loop

            if length(i) = 1
            then
                v_append := 0;
            else
                v_append := null;
            end if;
            v_p_year :=null;
            v_p_year := i+1;

            if length(v_p_year) = 1
            then
                v_p_check := v_year||trim(v_append)||v_p_year;
            else
                v_p_check := v_year||v_p_year;
            end if;
            dbms_output.put_line('v_p_check'||'='||v_p_check);
            if i=1 
            then
                v_sql := ' ALTER TABLE '||p_table_name||' ADD PARTITION P_'||v_year||trim(v_append)||i||' VALUES LESS THAN ('||v_p_check||')'||';';
            else
                v_sql := v_sql||chr(10)||' ALTER TABLE '||p_table_name||' ADD PARTITION P_'||v_year||trim(v_append)||i||' VALUES LESS THAN ('||v_p_check||')'||';';
            end if;

        end loop;
        dbms_output.put_line(v_sql);
        begin
            execute immediate ( v_sql );
        exception when others
        then
            p_status := 'F';
            p_messgae := 'Failure'||sqlerrm||dbms_utility.format_error_backtrace;
            return;
            dbms_output.put_line('exec'||sqlerrm||dbms_utility.format_error_backtrace);
        end;    
        exception when others
        then
            p_status := 'F';
            p_messgae := 'Failure'||sqlerrm||dbms_utility.format_error_backtrace;
            return;
            dbms_output.put_line('dynamic_proc'||sqlerrm||dbms_utility.format_error_backtrace);
        end;

        end;



        For Execution
        -----------------------------------------
        declare
                p_status   varchar2(1);
                p_message  varchar2(4000);
        begin
                shs_pk_dyn_par.dynamic_proc('EMPLOYEES_PAR',201302,201311,p_status,p_message);
                dbms_output.put_line('p_status'||'='||p_status||'='||'p_messgae'||'='||p_message);
        end;

1 个答案:

答案 0 :(得分:1)

分号是一个语句分隔符;这是无效的角色。您只能使用execute immediate执行单个语句,不能一次性构建一系列SQL语句并执行它们。因此,您需要删除分号并将execute immediate移动到循环中,删除语句的串联,并从每个单独的语句中删除最后一个分号:

begin
    ...
    loop
        ...
        dbms_output.put_line('v_p_check'||'='||v_p_check);
        v_sql := ' ALTER TABLE '||p_table_name
            ||' ADD PARTITION P_'||v_year||trim(v_append)||i
            ||' VALUES LESS THAN ('||v_p_check||')';
        dbms_output.put_line(v_sql);
        execute immediate ( v_sql );
    end loop;
exception when others
then
    p_status := 'F';
    p_messgae := 'Failure'||sqlerrm||dbms_utility.format_error_backtrace;
    return;
end;

(添加换行符只是为了停止代码滚动)

你也需要查看你的异常处理程序;我可能只是删除了附加到该子块的版本,因为它似乎有点无意义,但如果你真的想要,你仍然可以将每个调用包装在它自己的块中。

我认为你根本不需要任何异常处理程序 - 不确定为什么你不会让调用者自己处理异常而不是必须设置out参数。捕获others通常是一个坏主意。偶然地,return之后的代码永远不会被调用。但这有点偏离主题......