Как выполнить процедуру Dynami c - PullRequest
0 голосов
/ 30 января 2020

Я пытаюсь создать динамическую c процедуру, которая заполняет таблицу данными, уже существующими в таблице. У меня есть две переменные для первичного столбца, а не столбцы первичного ключа. Я передал последовательность (generate.nextval) в столбец первичного ключа. Он будет вставлять указанное c количество строк, которое передается как параметр (количество)

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: Обнаружен символ "выбрать ЗАМЕНИТЬ (ЗАМЕНИТЬ (REPLACE (xmlagg)") (xmlforest (cols.column_name "при ожидании одного из следующих действий: (выберите символ" выберите "вместо" выберите ЗАМЕНИТЬ (ЗАМЕНИТЕ (ЗАМЕНИТЕ (xmlagg (xmlforest (cols.column_name ", чтобы продолжить. PLS-00103: обнаружен символ) «;» при ожидании одного из следующего:, * & - + / в оставшейся части мода rem начиная с ||

Ответы [ 2 ]

0 голосов
/ 31 января 2020

Вам не нужна динамическая c строка для курсора, и вам не нужно жонглировать с помощью 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;

Помните, что процедура завершится ошибкой, если ваша таблица имеет составной первичный ключ, т. Е. Построение первичного ключа более чем на один столбец. Он также завершается ошибкой, если ваша таблица вообще не имеет первичного ключа.

Возможно, вам следует пропустить первичный ключ и применить generate.nextval через триггер BEFORE INSERT на уровне строк.

Примечание, также 17 лет Oracle 10g уже поддерживал современный синтаксис соединения ANSI.

0 голосов
/ 30 января 2020

Не думаю, что вам нужен динамический запрос c для курсоров.

Используйте следующий код и дайте мне знать, если он работает:

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;

Cheers !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...