我有一个使用 For循环的PL / SQL过程,并插入了大约5000条记录。
由于 For循环出现性能问题,因此我尝试使用 FORALL 。
我正在传递表名称,序列ID,列名称列表( I_columnnames 作为逗号分隔的字符串),列数据类型(作为逗号分隔的字符串),多个记录级别数据(作为逗号分隔的字符串)
I_columnnames 将具有多个列名(每次执行的列数各不相同) 我已经按照一个集合 v_tab 中的相应数据类型格式化了每个记录级别的数据(例如,'REC01',1500,100,100,TO_TIMESTAMP('2019-10-10','YYYY- MM-DD HH:MM:SS.FF3'))
现在,我必须在该动态表中插入记录级别的数据,为此,我正在使用FORALL语句,其执行立即执行如下:
FORALL i IN v_tab.first .. v_tab.last
EXECUTE IMMEDIATE 'INSERT INTO ' ||I_tablename||' (BLCK_ID, SEQ_ID, '||I_columnnames|| ')
values ('''|| I_blckid||''' ,'||I_sequence||' ,'||':1'||')' using v_tab(i);
但是我得到 ORA-值不足错误,因为绑定变量:1被认为是单个字符串(尽管它具有多个逗号分隔的值)
请帮助。
答案 0 :(得分:1)
:1
是一个包含逗号分隔值的单个字符串,它不会扩展到所有单个元素。
您发现,请串联字符串:
...I_sequence||' ,'|| v_tab(i) ||')';
得到“ PLS-00435:不能在FORALL内部使用没有BULK In-BIND的DML语句。”
您仍然可以连接字符串,但是可以在普通的for
循环中而不是在forall
中进行连接:
for i in v_tab.first .. v_tab.last loop
execute immediate 'INSERT INTO ' ||i_tablename||' (BLCK_ID, SEQ_ID, '||i_columnnames|| ')'
|| ' values ('''|| i_blckid||''' ,'||i_sequence||' ,' || v_tab(i) || ')';
end loop;
假定您的CSV字符串中包含适当的引号并进行任何必要的转换,尽管您的示例无效,这似乎是事实-从SQL注入的角度来看这是有风险的。
您可以考虑使用dbms_sql
而不是execute immediate
,但我认为不会带来太大的改进。您可能最好重新考虑构造v_tab
的方式和原因。您还可以在现有的PL / SQL块中使用通过操纵字符串构建的动态PL / SQL块;但是只有5000行时,通过简单循环获得的任何速度或效率提高都不值得。但这可以避免SQL注入问题。
答案 1 :(得分:0)
extension Double {
func toFahrenheit() -> Double {
// current temperature is always in Kelvin
let temperature = Measurement<UnitTemperature>(value: self, unit: .kelvin)
let formatter = MeasurementFormatter()
formatter.numberFormatter.maximumFractionDigits = 0
// convert to fahrenheit from Kelvin
let convertedTemperature = temperature.converted(to: .fahrenheit)
return Double(formatter.string(from: convertedTemperature))!
}
中的 EXECUTE IMMEDIATE
无法正常工作。
使用FORALL
代替常规的INSERT ALL
可以很好地工作并改善了性能。