【问题标题】:Using bind variables with dynamic SELECT INTO clause in PL/SQL在 PL/SQL 中使用带有动态 SELECT INTO 子句的绑定变量
【发布时间】:2011-12-10 14:40:58
【问题描述】:

我有一个关于在 PL/SQL 的动态 SQL 语句中可以在何处使用绑定变量的问题。

例如,我知道这是有效的:

CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
RETURN NUMBER
IS
  v_query_str VARCHAR2(1000);
  v_num_of_employees NUMBER;
BEGIN
  v_query_str := 'SELECT COUNT(*) FROM emp_' 
                 || p_loc
                 || ' WHERE job = :bind_job';                           
  EXECUTE IMMEDIATE v_query_str
    INTO v_num_of_employees
    USING p_job;
  RETURN v_num_of_employees;
END;
/

我想知道你是否可以在这样的选择语句中使用绑定变量

CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
RETURN NUMBER
IS
  v_query_str VARCHAR2(1000);
  v_num_of_employees NUMBER;
BEGIN
  v_query_str := 'SELECT COUNT(*) INTO :into_bind FROM emp_' 
                 || p_loc
                 || ' WHERE job = :bind_job';                           
  EXECUTE IMMEDIATE v_query_str
    USING out v_num_of_employees, p_job;
  RETURN v_num_of_employees;
END;
/

注意,我使用 SELECT INTO 语句作为动态字符串,并在 INTO 子句中使用了绑定变量。

我现在正在旅行,几天之内将无法在家中使用我的电脑,但这一直困扰着我。尝试阅读 PL/SQL 参考,但他们没有这样的选择示例。

谢谢

【问题讨论】:

标签: sql oracle plsql oracle11g execute-immediate


【解决方案1】:

Select Into 功能仅适用于 PL/SQL Block,当您使用 Execute immediate 时,oracle 将 v_query_str 解释为 SQL Query 字符串,因此您不能使用 into 。将获得关键字丢失异常。 在示例 2 中,我们使用 begin end;所以它变成了 pl/sql 块并且它是合法的。

【讨论】:

    【解决方案2】:

    绑定变量可以在带有“in”子句的Oracle SQL查询中使用。

    在 10g 中工作;其他版本不知道。

    绑定变量是 varchar,最多 4000 个字符。

    示例:绑定包含逗号分隔值列表的变量,例如

    :bindvar = 1,2,3,4,5

    select * from mytable
      where myfield in
        (
          SELECT regexp_substr(:bindvar,'[^,]+', 1, level) items
          FROM dual
          CONNECT BY regexp_substr(:bindvar, '[^,]+', 1, level) is not null
        );
    

    (与我在此处发布的相同信息:How do you specify IN clause in a dynamic query using a variable?

    【讨论】:

      【解决方案3】:

      不,您不能那样使用绑定变量。在您的第二个示例中,v_query_str 中的:into_bind 只是变量v_num_of_employees 的值的占位符。您的 select into 语句将变成如下内容:

      SELECT COUNT(*) INTO  FROM emp_...
      

      因为v_num_of_employees 的值是null EXECUTE IMMEDIATE

      您的第一个示例展示了将返回值绑定到变量的正确方法。

      编辑

      原始海报编辑了我在回答中提到的第二个代码块,以使用 v_num_of_employeesOUT 参数模式而不是默认的 IN 模式。此修改使两个示例在功能上等效。

      【讨论】:

      • 哦,有道理,':into_bind' 在实际运行时会被替换。在我写的第一个例子中,它仍然会在 INTO 子句中使用绑定变量吗?我想尝试第二种方式的原因是因为它使用了绑定变量。
      • @BYS2:是的,您可以使用OUT参数模式。不过,为了清楚起见,我更喜欢EXECUTE IMMEDIATE INTO
      【解决方案4】:

      在我看来,动态 PL/SQL 块有些晦涩难懂。虽然非常灵活,但也难以调整、难以调试并且难以弄清楚发生了什么。 我的投票投给你的第一个选项,

      EXECUTE IMMEDIATE v_query_str INTO v_num_of_employees USING p_job;
      

      两者都使用绑定变量,但首先,对我来说,它比 @jonearles 选项更可重用和可调整。

      【讨论】:

      • 好的,谢谢你的信息,因为两者都使用绑定变量,第一个选项似乎是最好的!
      • @BYS2:我也最喜欢这种语法。不知道性能。
      【解决方案5】:

      将 select 语句放在动态 PL/SQL 块中。

      CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
      RETURN NUMBER
      IS
        v_query_str VARCHAR2(1000);
        v_num_of_employees NUMBER;
      BEGIN
        v_query_str := 'begin SELECT COUNT(*) INTO :into_bind FROM emp_' 
                       || p_loc
                       || ' WHERE job = :bind_job; end;';
        EXECUTE IMMEDIATE v_query_str
          USING out v_num_of_employees, p_job;
        RETURN v_num_of_employees;
      END;
      /
      

      【讨论】:

      • 啊,我明白了,谢谢!顺便说一句,您知道哪种方式更好吗?像您一样将 SELECT INTO 封装在一个块中,或者像我在第一个示例中那样使用 EXECUTE IMMEDIATE 语句的 INTO 子句。两者都使用绑定变量吗?效率有什么不同?
      • 我同意其他人的观点,即第一种方法(动态 SQL)比第二种方法(动态 PL/SQL)要好得多。动态 PL/SQL 非常少见,几乎从不需要。基于一些简单的测试,我没有看到两者之间的任何性能差异,但我预计动态 PL/SQL 方法在某些情况下会稍微慢一些。动态 PL/SQL 方法实际上生成 3 个绑定变量:2 个用于 PL/SQL 块(尽管在 V$SQL_BIND_CAPTURE 中都没有捕获),1 个用于 SQL 查询。像这样的怪癖会使调优和调试变得非常困难。
      • 哦,好的,非常感谢您的建议!无法将您的答案作为答案,因为从技术上讲,这不是我的问题,但我完全愿意学习,所以很高兴知道这一点:D
      • 这是最有意义的。请记住,它是在 PLSQL(正确的术语?)之外执行的,就像您在 SQLPlus 命令提示符下看到的那样,这就是为什么您可以从 exec immed 执行 DDL。
      猜你喜欢
      • 2022-12-11
      • 2017-11-09
      • 2011-04-06
      • 2014-09-17
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-24
      • 1970-01-01
      相关资源
      最近更新 更多