所以我有一个用于更新某个表的存储过程,其中表的名称是根据参数v_example
输入的。
PROCEDURE update_name(example_id NUMBER, v_example VARCHAR2, lcursor out rcursor)
AS
v_sequel VARCHAR2(10000);
Begin
UPDATE T_EXAMPLE_'||v_example||'_L1 SET T_EXAMPLE_'||v_example||'_L1.SUM1 = (SELECT T_SDEXAMP_'||v_example||'.SUM1
FROM T_SDEXAMP_'||v_example||'
WHERE T_SDEXAMP_'||v_example||'.BILATERAL_ID = T_EXAMPLE_'||v_example||'_L1.BILATERAL_ID),
T_EXAMPLE_'||v_example||'_L1.SUM2 = (SELECT T_SDEXAMP_'||v_example||'.SUM2
FROM T_SDEXAMP_'||v_example||'
WHERE T_SDEXAMP_'||v_example||'.BILATERAL_ID = T_EXAMPLE_'||v_example||'_L1.BILATERAL_ID),
T_EXAMPLE_'||v_example||'_L1.SUM3 = (SELECT T_SDEXAMP_'||v_example||'.SUM3
FROM T_SDEXAMP_'||v_example||'
WHERE T_SDEXAMP_'||v_example||'.BILATERAL_ID = T_EXAMPLE_'||v_example||'_L1.BILATERAL_ID)
WHERE T_EXAMPLE_'||v_example||'_L1.BILATERAL_ID = '||example_id||';
COMMIT;
End;
因此,正如您所看到的,我希望表名为T_EXAMPLE_的组合,参数为v_example,_L1 ...
当我执行上面的脚本时,它给了我这个错误:
ERROR line 1076, col 18, ending_line 1076, ending_col 32, Found ''||v_example||'', Invalid identifier: '||v_example||'
有人能帮助我吗?感谢....
答案 0 :(得分:4)
在过程中定义的静态SQL中,必须定义标识符(表名,列名)并在编译时可用。
为了达到你想要实现的目的......在SQL语句中动态指定表名,你必须使用某种形式的"动态SQL"。
在Oracle程序中这样做的老派方式是使用DBMS_SQL
包。后来,Oracle引入了EXECUTE IMMEDIATE
。之后,Oracle添加了CURSOR FOR
语法。可能还有更新的方法。
所有这些模式都有相似之处。我不打算全部为您编写,或重复Oracle文档中提供的信息。
以下是EXECUTE IMMEDIATE的示例。动态创建SQL字符串,使所有标识符(列名,table_names,函数等)成为静态SQL文本的一部分。并使用绑定占位符来传递您想要传入的值。
... PROCEDURE doit2it(v_id INT, v_example VARCHAR, ... )
AS
v_sql VARCHAR(1023);
BEGIN
v_sql := 'T_EXAMPLE_'||v_example||'_L1'
|| ' SET T_EXAMPLE_'||v_example||'_L1.SUM1 = '
|| ' ...'
|| ' WHERE col = :b1 ';
EXECUTE IMMEDIATE v_sql USING v_id ;
同样,EXECUTE IMMEDIATE
并不是执行动态SQL的唯一机制,但与使用DBMS_SQL
包相比,它的代码要清晰得多。
由于SQL语句的文本是字符串,因此您可以使用DBMS_OUTPUT.PUT_LINE在执行之前输出SQL文本,这有助于调试。
<强>后续强>
在该示例中,v_id
的值被传递给SQL语句的执行,该语句作为绑定占位符:b1
的值提供。
如果SQL中有两个占位符,则传入两个值,例如:
USING v_id, v_name
由于绑定是位置的(而不是名称),我倾向于使用:b1
,:b2
,:b3
等作为SQL文本中的占位符。但我认为你可以使用任何有效的名称。 &#34;无名&#34;绑定占位符的编号有助于提醒我它是按位置,而不是按名称。如果我需要传递两次相同的值,我会为绑定占位符使用不同的名称并提供两次值,例如
EXECUTE IMMEDIATE '... foo = :b1 AND bar = :b2 ...' USING v_id, v_id;
使用绑定占位符和传入值的模式类似于在幕后发生的事情&#34; (实际上)PL / SQL块中的 static SQL引用了PL / SQL变量。例如:
v_name VARCHAR(30) := 'douglas adams' ;
v_id INT := 42 ;
UPDATE mytable SET myname = v_name WHERE myid = v_id ;
编译PL / SQL时,会检查SQL语句,并将其转换为SQL文本,如下所示:
UPDATE mytable SET myname = :b1 WHERE myid = :b2
在执行时,为绑定占位符提供v_name
和v_id
的值。与我们在动态SQL示例中所做的类似。
答案 1 :(得分:1)
您的陈述似乎有误,我认为您可以将其分类:
v_sql := 'UPDATE T_EXAMPLE_'||v_example||'_L1 SET
(SUM1, SUM2, SUM3) =
(SELECT SUM1, SUM2, SUM3
FROM T_SDEXAMP_'||v_example||'
WHERE T_SDEXAMP_'||v_example||'.BILATERAL_ID = T_EXAMPLE_'||v_example||'_L1.BILATERAL_ID)
WHERE BILATERAL_ID = :excample_id';
EXECUTE IMMEDIATE v_sql USING example_id;
在DBMS_OUTPUT.PUT_LINE(v_sql);
之前(或代替)调用EXECUTE IMMEDIATE
以验证更新声明。