Oracle PL/SQL 动态 if 语句全局变量

Posted

技术标签:

【中文标题】Oracle PL/SQL 动态 if 语句全局变量【英文标题】:Oracle PL/SQL dynamic if statement global vars 【发布时间】:2016-09-09 16:37:43 【问题描述】:

我在使用动态 sql 时遇到问题,问题是(我认为)读取和设置全局变量。这就是我所拥有的,非常感谢任何帮助。尽管我已将数据包含在 cmets 中,但如果您也需要表格数据,请告诉我。

 CREATE OR REPLACE PACKAGE data_load
    IS
      curr_rec          NUMBER;
      curr_rule         VARCHAR2(200);
      curr_sql          VARCHAR2(4000);
      curr_sql_two      VARCHAR2(4000);
      curr_data_element VARCHAR2 (200);
      curr_rule_text    VARCHAR2(200);
      curr_error_code   VARCHAR2(10);
      curr_error_flag   VARCHAR2(10);
      curr_flag_val     NUMBER;
      v_check           NUMBER;
      v_ID              NUMBER;
      cur_hdl           INT ;
      rows_processed    NUMBER;
      PROCEDURE check_rules;
    END data_load;

包体:

    create or replace PACKAGE BODY data_load IS
      PROCEDURE check_rules IS
        CURSOR c1
        IS
          SELECT * FROM STAGING_TABLE where rownum < 3;
        CURSOR c2
        IS
          SELECT * FROM ERROR_CODES WHERE rule_text IS NOT NULL AND status =1;
      BEGIN
        FOR rec1 IN c1
        LOOP
          FOR rec2 IN c2
          LOOP
            curr_data_element := 'rec1.'||rec2.data_element; --- this results in value  "rec1.SHIP_FROM_ACCOUNT_ORG_CODE" without quotes
            curr_rule_text    := rec2.rule_text; --- this value is "is not null" without quotes
            curr_error_flag   := rec2.error_flag; --this value is "FLAG_03" without quotes
            curr_flag_val     := to_number(rec2.error_code); --- this value is 31
            curr_sql :='begin if  :curr_data_element  '||curr_rule_text||'  then update table_with_column_FLAG_03  set  '||curr_error_flag ||' =  0; else  update table_with_column_FLAG_03 set  '||curr_error_flag ||' =  '||curr_flag_val||';  end if; end;';
            dbms_output.put_line(curr_sql); -- results in "begin if  :curr_data_element  is null  then update table_with_column_FLAG_03  set  FLAG_03 =  0; else  update table_with_column_FLAG_03 set  FLAG_03 =  31;  end if; end;"
            EXECUTE IMMEDIATE curr_sql USING curr_data_element ; -- this always  updates the column with 31 even when curr_data_element/ rec1.SHIP_FROM_ACCOUNT_ORG_CODE is null and that's the problem
            COMMIT;
          END LOOP;
          curr_rec := curr_rec+1;
        END LOOP;
        dbms_output.put_line(curr_rec);
      END check_rules;
    END data_load;

【问题讨论】:

关注问题...也发布表 ddl 发布表 ddl 为好 我将添加表格 ddl,但请在代码中查看我的 cmets 以了解问题, 【参考方案1】:

你已经真正强调了这个问题:

    curr_data_element := 'rec1.'||rec2.data_element; --- this results in value  "rec1.SHIP_FROM_ACCOUNT_ORG_CODE" without quotes

您不能动态引用游标列。您正在创建一个值为 'rec1.SHIP_FROM_ACCOUNT_ORG_CODE' 的字符串;没有机制来评估它代表什么。例如,您不能尝试从 dual 中动态选择它,因为 rec1 不在 SQL 调用的范围内,即使是动态的。

当您绑定该字符串值时,它永远不会为空。您使用的是该字符串,而不是它所代表的外部光标中的值,基本上您不能这样做。

如果您的临时表中有相当少量的列可能显示为 rec2.data_element 值,则处理此问题的最简单方法是使用 case 表达式来分配适当的实际 rec1 列值到curr_data_element 变量,基于 rec2.data_element 值:

...
  BEGIN
    FOR rec1 IN c1
    LOOP
      FOR rec2 IN c2
      LOOP
        curr_data_element :=
          case rec2.data_element
            when 'SHIP_FROM_ACCOUNT_ORG_CODE' then rec1.SHIP_FROM_ACCOUNT_ORG_CODE
            when 'ANOTHER_COLUMN' then rec1.ANOTHER_COLUMN
            -- when ... -- repeat for all possible columns
          end;            
        curr_rule_text    := rec2.rule_text;
...

如果您有很多列,您可能会通过集合来做到这一点,但这可能不值得付出额外的努力。

curr_sql 字符串保持不变,所有变化在于您正在绑定来自相关 rec1 列的实际值,而不是您正在形成的永不空字符串。

【讨论】:

谢谢亚历克斯,我在某处读到全局变量可以以我需要的方式引用它们您对我如何实现这一点有任何意见吗? @oracle_of - 全局(但可能是本地)变量 curr_data_element 可以如您所示引用,并使用绑定变量。那部分没问题。问题是该变量包含什么。您不能拥有一个本质上是指向另一个 PL/SQL 变量的指针的变量。没有评估包含 PL/SQL 变量名的字符串的机制。

以上是关于Oracle PL/SQL 动态 if 语句全局变量的主要内容,如果未能解决你的问题,请参考以下文章

Oracle_PL/SQL 动态sql

Oracle之PL/SQL编程_流程控制语句

带有 IF 语句的 PL/SQL Oracle 查询

oracle pl/sql 控制结构(分支,循环,控制)

oracle pl/sql中的循环及if语句

Oracle pl sql 动态使用子句