我有下面的过程,没有错误消息:
create or replace procedure insert_or_upd_movement_baselines_planned_weight_proc(
p_id IN VARCHAR2,
p_date IN DATE,
p_planned_col_name IN VARCHAR2,
p_planned_value IN NUMBER
) as
begin
declare
plsql_block NVARCHAR2(8000);
begin
plsql_block := 'merge into MOVEMENT_BASELINES mb using dual on (mb.MOVEMENT_ID = ' || p_id || ' and mb.MOVEMENT_DATE = ' || p_date || ')
when not matched then insert (mb.MOVEMENT_ID, mb.MOVEMENT_DATE, mb.' || p_planned_col_name || ')
values ( ' || p_id || ', ' || p_date || ', ' || p_planned_value || ')
when matched then update set '
|| p_planned_col_name || ' = ' || p_planned_value || ';';
execute immediate plsql_block;
end;
end insert_or_upd_movement_baselines_planned_weight_proc;
当我尝试使用输入参数的值执行它时,我得到了一个编译器错误:
Connecting to the database localDB.
ORA-00933: SQL command not properly ended
ORA-06512: at "RTT.INSERT_OR_UPD_MOVEMENT_BASELINES_PLANNED_WEIGHT_PROC", line 17
ORA-06512: at line 12
Process exited.
我是Oracle的新手,想打印动态SQL来检查什么是错误的,但打印语句似乎不起作用。我猜问题是插入语句中的动态列名-知道什么是错误的吗?谢谢
3条答案
按热度按时间2admgd591#
在使用动态SQL时,您应该始终保持谨慎。首先,最好检查静态SQL语句是否正常工作,然后尝试通过修改动态部分来转换它。此外,
execute immediate
之前的dbms_output
可以帮助您了解准备好的SQL是否语法正确。其次,连接值容易发生 *SQL注入 *,应该避免。首选选项是使用绑定变量和EXECUTE IMMEDIATE
的USING
选项。由于
p_planned_value
被定义为一个数字,这意味着你计划更新/插入的所有列的数据类型都将是整数。我在演示的例子中相应地使用了它。如果不是这样,你将不得不重新考虑如何定义过程的参数,以便它适用于其他情况,如DATE
数据类型。Demo
9rbhqvlz2#
这部分肯定是鱼腥味:
因为它实际上也是
因此,日期的未加引号的值成为语句的一部分,这将不会导致有效的sql语句。请尝试以下操作:
ac1kyiln3#
这是Kaushik的回答的补充,他们指出(非常正确,如果不是那么多话)您的语句完全容易受到SQL注入的影响。
我会把你的程序写如下:
请注意使用
dbms_assert
来清理输入-在本例中,我们检查传入p_planned_col_name的值是否满足有效标识符的要求,这意味着它绝对不能用于SQL注入。此外,我将参数移到子查询中,这意味着立即执行的
using
子句现在更短,而且我认为更清晰,更易于维护。