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 语句全局变量的主要内容,如果未能解决你的问题,请参考以下文章