检查包 DBMS_SQL,在那里你可以找到所有的程序。一个未经测试的例子是这个:
CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
create or replace PROCEDURE INSERT_DYN(
par_table_name_a IN VARCHAR2,
par_keys_a IN VARCHAR_TABLE_TYPE,
par_values_a IN VARCHAR_TABLE_TYPE) as
cur INTEGER;
res INTEGER;
sqlcmd VARCHAR2(10000);
begin
sqlcmd := 'INSERT INTO '||par_table_name_a||' (';
FOR i in par_keys_a.first..par_keys_a.last loop
sqlcmd := sqlcmd ||par_keys_a(i)||',';
end loop;
sqlcmd := REGEXP_REPLACE(sqlcmd, ',$', ')');
sqlcmd := sqlcmd||' values ('
FOR i in par_keys_a.first..par_keys_a.last loop
sqlcmd := sqlcmd ||':b'||i||',';
end loop;
sqlcmd := REGEXP_REPLACE(sqlcmd, ',$', ')');
-- Check if command is properly composed:
DBMS_OUTPUT.PUT_LINE(sqlcmd);
cur := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cur, sqlcmd, DBMS_SQL.NATIVE);
FOR i in par_keys_a.first..par_keys_a.last loop
DBMS_SQL.BIND_VARIABLE(cur, ':b'||i, par_values_a(i));
END LOOP;
res := DBMS_SQL.EXECUTE(cur);
DBMS_SQL.CLOSE_CURSOR(cur);
end;
一个数组(在 Oracle 中称为“嵌套表”)只包含相同数据类型的元素,这里我取的是 VARCHAR2。对于 NUMBER 类型的值,使用相同的嵌套表没有问题。对于 DATE 或类似的值,您必须做一些技巧,例如使用一些模式和正则表达式或提供另一个包含每个字段的数据类型的嵌套表。
另一种解决方案是跳过绑定变量并进行硬解析,即替换它
sqlcmd := sqlcmd||' values ('
FOR i in par_keys_a.first..par_keys_a.last loop
sqlcmd := sqlcmd ||':b'||i||',';
end loop;
sqlcmd := REGEXP_REPLACE(sqlcmd, ',$', ')');
...
END;
这个
sqlcmd := sqlcmd||' values ('
FOR i in par_keys_a.first..par_keys_a.last loop
sqlcmd := sqlcmd ||''''||par_values_a(i)||''',';
end loop;
sqlcmd := REGEXP_REPLACE(sqlcmd, ',$', ')');
EXECUTE IMMEDIATE sqlcmd;
END;
但是,这为 SQL 注入打开了大门,您仍然会遇到除 VARCHAR 或 NUMBER 之外的其他数据类型的问题