Oracle - 存储过程。更新表,根据参数使用表名

时间:2016-04-08 03:48:00

标签: oracle stored-procedures

所以我有一个用于更新某个表的存储过程,其中表的名称是根据参数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||'

有人能帮助我吗?感谢....

2 个答案:

答案 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_namev_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以验证更新声明。