【问题标题】:String concatenation select query is not giving result pl/sql script字符串连接选择查询未给出结果 pl/sql 脚本
【发布时间】:2023-04-01 06:38:01
【问题描述】:

我正在尝试动态构造查询,但在字符串连接之后,select 语句在 pl/sql 中没有产生任何结果。

请帮帮我

DECLARE
  person_id NUMBER;
BEGIN
  DECLARE
    age_where VARCHAR2(100 CHAR);
    TEMP_WHERE     VARCHAR2(100 CHAR) := '';
    add_temp_where BOOLEAN            := true;
    
  begin
    age_where := q'[ and age=28]';
    
    IF(ADD_TEMP_WHERE) THEN
      TEMP_WHERE := age_where;
    END IF;
    
  SELECT id INTO person_id FROM PERSON WHERE name = 'David' || TEMP_WHERE ;
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('no data');
  END;
  DBMS_OUTPUT.PUT_LINE('result : ' || person_id);
END;

表格条目

ID      NAME        AGE     ADDRESS     SALARY
-----------------------------------------------
1       David       28      PURAM       30000
2       Vimal       30      MARUR       20000

输出:

anonymous block completed
no data
result : 

【问题讨论】:

  • 您必须使用 execute immediate 来运行动态 SQL。还有一个 hint 使用 bind variables 而不是谓词字符串连接。

标签: oracle plsql concatenation


【解决方案1】:

为此,您需要动态 SQL。

SQL> DECLARE
  2     person_id       NUMBER;
  3     age_where       VARCHAR2 (100 CHAR);
  4     TEMP_WHERE      VARCHAR2 (100 CHAR) := '';
  5     add_temp_where  BOOLEAN := TRUE;
  6     l_str           VARCHAR2 (400);
  7  BEGIN
  8     age_where := q'[ and age=28]';
  9
 10     IF (ADD_TEMP_WHERE)
 11     THEN
 12        TEMP_WHERE := age_where;
 13     END IF;
 14
 15     l_str := q'[SELECT id FROM PERSON WHERE name = 'David']' || TEMP_WHERE;
 16
 17     EXECUTE IMMEDIATE l_str
 18        INTO person_id;
 19
 20     DBMS_OUTPUT.PUT_LINE ('result : ' || person_id);
 21  END;
 22  /
result : 1

PL/SQL procedure successfully completed.

SQL>

【讨论】:

    【解决方案2】:

    您的目标是根据输入参数在查询中使用动态谓词。这是一项频繁的任务。

    最重要的想法是意识到,您应该始终使用绑定变量进行生产查询,即ommit构造,例如WHERE name = 'David' || TEMP_WHERE

    PL/SQL 中有三个选项

    使用 IF - ELSE

    这是最简单的选项,输入参数的每个组合都有一个 IF/ELSE 分支

    declare
     l_person_id  int;
     l_name varchar2(10) := 'David';
     l_age int := 28;
     add_temp_where int := 1; 
    begin
      if add_temp_where = 0 then
        select id into l_person_id from person where name = l_name;
      else
        select id into l_person_id from person where name = l_name and age = l_age;
      end if;  
      dbms_output.put_line(l_person_id);    
    end;
    /
    

    这将在您的情况下使用一个可选参数,但对于更多参数是不切实际的。对于 3 个参数,您将需要 8 个分支。

    使用 OR 禁用谓词

    此选项仅使用一个 static 语句并使用OR 逻辑来禁用不需要的参数。

    请注意,我使用参数add_temp_whereint 0,1 以便能够在SQL 中使用它。

    declare
     l_person_id  int;
     l_name varchar2(10) := 'David';
     l_age int := 28;
     add_temp_where int := 1; 
    begin
      select id into l_person_id from person where name = l_name and (add_temp_where = 0 or age = l_age);
      dbms_output.put_line(l_person_id);    
    end;
    /
    

    所以基本上如果add_temp_where = 0 比谓词age = l_age 由于快捷评估而被忽略。

    如果对于所有选项,查询返回相似的行数(技术上使用相同的执行计划),此选项可以正常工作。

    如果一个选项返回整个表,而另一个选项返回一小部分(通过索引),它严重失败

    在这种情况下,您需要使用动态 SQL。

    动态 SQL

    您使用与上面相同的技巧 OR,因此您生成以下 SQL 字符串

    -- for  add_temp_where = 1
    select id  from person where name = :1 and age = :2
    -- for  add_temp_where = 0
    select id  from person where name = :1 and (0=0 or age = :2)'
    

    请注意,这两个语句都有两个绑定变量,因此它们可以在一个EXECUTE IMMEDIATE 中使用,如下所示:

    declare
     l_person_id  int;
     l_name varchar2(10) := 'David';
     l_age int := 28;
     add_temp_where BOOLEAN := true;
     --
     l_sql1 varchar2(1000) := 'select id  from person where name = :1 and age = :2';
     l_sql2 varchar2(1000) := 'select id  from person where name = :1 and (0=0 or age = :2)'; 
    begin
      execute immediate l_sql1 into l_person_id using l_name, l_age;
      dbms_output.put_line(l_person_id); 
      execute immediate l_sql2 into l_person_id using l_name, l_age;
      dbms_output.put_line(l_person_id);   
    end;
    /
    

    两个语句是独立的,因此可以有不同的执行计划,这解决了第二个选项的问题。

    更多信息和归功于此选项herehere

    【讨论】:

    • 感谢您的建议@Marmite Bomber
    猜你喜欢
    • 1970-01-01
    • 2021-11-03
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    相关资源
    最近更新 更多