Вам не нужна динамическая 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.