【问题标题】:How to execute dynamic procedure如何执行动态过程
【发布时间】:2020-01-30 11:59:54
【问题描述】:

我正在尝试创建一个动态过程,该过程填充表中已存在的数据中的表。我有两个主列变量,而不是主键列。我将一个序列(generate.nextval)传递给主键列。它将插入作为参数(数量)传递的特定行数

Create or replace procedure v_populate (table_name in varchar2, amount in number)
IS
v_pk varchar2(1000);
v_pk2 varchar2(1000);
V_dyntask LONG;
V_dyntask2 LONG;

CURSOR C1 IS 
'select REPLACE(REPLACE(REPLACE(xmlagg(xmlforest(cols.column_name ) 
ORDER BY cols.column_name ),''</COLUMN_NAME><COLUMN_NAME>'','',''),''<COLUMN_NAME>''),''</COLUMN_NAME>'') XMLAGG  --cols.column_name 
FROM all_constraints cons, all_cons_columns cols
WHERE cols.table_name ='''||table_name||'''AND cons.constraint_type NOT IN (''P'',''U'',''R'')
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position';

CURSOR C2 IS
'select 
                    REPLACE( 
                      REPLACE(
                        REPLACE(xmlagg(xmlforest(cols.column_name ) ORDER BY cols.column_name )
                               ,''</COLUMN_NAME><COLUMN_NAME>'','','')
                              ,''<COLUMN_NAME>'')
                             ,''</COLUMN_NAME>'') XMLAGG --cols.column_name 
               FROM all_constraints cons, all_cons_columns cols
              WHERE cols.table_name ='''||table_name||'''
                AND cons.constraint_type = ''P''
                AND cons.constraint_name = cols.constraint_name
                AND cons.owner = cols.owner
           ORDER BY cols.table_name, cols.position
              ';

BEGIN

FOR F1 in C1 
LOOP
v_pk:=C1.COLUMN_NAME;
END LOOP;

FOR F2 in C2 
LOOP
v_pk2:=C2.COLUMN_NAME;
END LOOP;

V_dyntask2:= 'INSERT INTO ' ||table_name|| ' 
                        ( '||v_pk2||' , '||v_pk||' ) 
                 select generate.nextval,'||v_pk||' 
                   from ' ||table_name || '
                  where rownum <='||amount;
EXECUTE IMMEDIATE V_dyntask2;
COMMIT;
end;

我不断收到此错误: PLS-00103:遇到符号“select REPLACE(REPLACE(REPLACE(xmlagg(xmlforest(cols.column_name)”时,期望以下之一:( select 符号“select”被替换为“select REPLACE(REPLACE(REPLACE(xmlagg( xmlforest(cols.column_name" 继续。 PLS-00103:遇到符号“;”当期望以下之一时: , * & - + / at mod 余数 rem as from ||

【问题讨论】:

  • 我不会为你调试它。不过,有一条建议:不要执行它,而是先dbms_output.put_line(v_dyntask2) 并检查它是否看起来正常。当然不会——否则,它会起作用。在修复错误之前不要执行它。
  • 我现在试过了,它给出了同样的错误。我对 plsql 有点陌生,可能我错过了一些东西@Littlefoot
  • PL/SQL 新手?难道你找不到比动态 SQL 更简单的东西吗?好吧,您必须重新开始,逐步创建 v_dyntask2,经常进行测试。
  • 你的代码看起来很奇怪,你想达到什么目的?循环是无用的,您只需从查询中取出最后一行。在您的查询中,您首先使用 xmlagg(xmlforest(... 创建 XML 对象,然后再次删除 XML 标记以获取纯文本。
  • 数据类型 LONG 已弃用近 20 年,请勿使用。

标签: sql oracle stored-procedures plsql oracle-sqldeveloper


【解决方案1】:

我认为您不需要动态查询游标。

使用以下代码并告诉我它是否有效:

CREATE OR replace PROCEDURE V_POPULATE (
    P_TABLE_NAME   IN           VARCHAR2,
    AMOUNT       IN           NUMBER
)
IS
    V_PK VARCHAR2(1000);
    V_PK2 VARCHAR2(1000);
    V_DYNTASK LONG;
    V_DYNTASK2 LONG;

BEGIN

FOR F1 in (select REPLACE(REPLACE(REPLACE(xmlagg(xmlforest(cols.column_name ) 
ORDER BY cols.column_name ),'</COLUMN_NAME><COLUMN_NAME>',','),'<COLUMN_NAME>'),'</COLUMN_NAME>') column_name  --cols.column_name 
FROM all_constraints cons, all_cons_columns cols
WHERE cols.table_name = P_TABLE_NAME  
AND cons.constraint_type NOT IN ('P','U','R')
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position) 
LOOP
v_pk:=F1.COLUMN_NAME;
END LOOP;

FOR F2 in (select 
        REPLACE( 
          REPLACE(
            REPLACE(xmlagg(xmlforest(cols.column_name ) ORDER BY cols.column_name )
                   ,'</COLUMN_NAME><COLUMN_NAME>',',')
                  ,'<COLUMN_NAME>')
                 ,'</COLUMN_NAME>') column_name --cols.column_name 
   FROM all_constraints cons, all_cons_columns cols
  WHERE cols.table_name =P_table_name
    AND cons.constraint_type = 'P'
    AND cons.constraint_name = cols.constraint_name
    AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position) 
LOOP
v_pk2:=F2.COLUMN_NAME;
END LOOP; 

V_dyntask2:= 'INSERT INTO ' || P_table_name|| ' 
                        ( '||v_pk2||' , '||v_pk||' ) 
                 select generate.nextval,'||v_pk||' 
                   from ' ||P_table_name || '
                  where rownum <='||amount;
EXECUTE IMMEDIATE V_dyntask2;
COMMIT;
end;

干杯!!

【讨论】:

  • 感谢您的帮助@Tejash。但是现在它给出了这个错误:PLS-00302:必须声明组件“COLUMN_NAME”
  • 在游标中,没有 column_name 别名,所以它给出了错误。更新了答案。现在检查!
  • 谢谢@Tejash !!!现在我可以运行脚本而不会出错。我知道我问的太多了,但是当我执行该过程时,我收到一条错误消息:PLS-00357:Table,View Or Sequence reference 'EMPLOYEES' not allowed in this context.
【解决方案2】:

游标不需要动态字符串,也不需要处理 XML。我会像下面那样做。

CREATE OR REPLACE PROCEDURE v_populate (table_name IN VARCHAR2, amount IN NUMBER)

    v_pk VARCHAR2(1000);
    v_pk2 VARCHAR2(1000);
    sqlstr VARCHAR2(30000);

    CURSOR C1 IS
    SELECT cols.column_name
    FROM all_constraints cons
        JOIN all_cons_columns cols USING (OWNER, constraint_name)
    WHERE cols.table_name = table_name
        AND cons.constraint_type NOT IN ('P','U','R');
    ORDER BY cols.column_name; -- For check constraints ('C') POSITION is NULL, thus 'ORDER BY POSITION' is pointless!

    CURSOR C2 IS
    SELECT cols.column_name, cols.position
    FROM all_constraints cons
        JOIN all_cons_columns cols USING (OWNER, constraint_name)
    WHERE cols.table_name = table_name
        AND cons.constraint_type = 'P';

BEGIN

    sqlstr := 'INSERT INTO ' ||table_name|| ' ( ';
    FOR aCol IN C2 LOOP
        sqlstr := sqlstr || aCol.COLUMN_NAME||',';
    END LOOP;

    FOR aCol IN C1 LOOP
        sqlstr := sqlstr || aCol.COLUMN_NAME||',';
    END LOOP;
    sqlstr := REGEXP_REPLACE(sqlstr, ',$', ') ');

    sqlstr := sqlstr || 'SELECT generate.nextval,';
    FOR aCol IN C1 LOOP
        sqlstr := sqlstr || aCol.COLUMN_NAME||',';
    END LOOP;
    sqlstr := REGEXP_REPLACE(sqlstr, ',$', ' ');
    sqlstr := sqlstr || 'FROM ' ||table_name|| ' WHERE ROWNUM <= :a';

    DBMS_OUTPUT.PUT_LINE ( sqlstr ); -- Only for testing to verify the generated command

    EXECUTE IMMEDIATE sqlstr USING amount;

END;

请注意,如果您的表具有复合主键,则该过程将失败,即主键由多于一列构建。如果您的表根本没有主键,它也会失败。

也许您应该跳过主键并通过行级 BEFORE INSERT 触发器应用 generate.nextval

注意,还有 17 年历史的 Oracle 10g 已经支持现代 ANSI 连接语法。

【讨论】:

    猜你喜欢
    • 2015-10-13
    • 2018-07-02
    • 2020-04-04
    • 2014-12-07
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    相关资源
    最近更新 更多