ORACLE中EXECUTE IMMEDIATE语句中使用的where子句中需要使用动态变量

Posted

技术标签:

【中文标题】ORACLE中EXECUTE IMMEDIATE语句中使用的where子句中需要使用动态变量【英文标题】:Need to use dynamic variables in where clause used in EXECUTE IMMEDIATE statement in ORACLE 【发布时间】:2015-02-19 17:58:06 【问题描述】:

ORACLE(使用 SQL DEVELOPER)。 我需要正确构造 EXECUTE IMMEDIATE 语句。 我没有“创造”特权。任务是获取每个日期每个表格的行数,以获取表格/日期的动态列表。 我有以下内容:

 DECLARE CURSOR cur_table_name IS SELECT TABLE_NAME 
 FROM ALL_TABLES WHERE TABLE_NAME IN ('table_a', 'table_b', 'table_c');
 CURSOR cur_BEGIN_DATE IS 
  select to_date('2014-09-25 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + rownum -1 AS BEGIN_DATE,  
  to_date('2014-09-26 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + rownum -1 AS END_DATE from dual 
  Connect by level <= to_date('2014-09-30 00:00:00', 'YYYY-MM-DD HH24:MI:SS') - to_date('2014-09-25 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + 1;

    var_total_rows NUMBER(15);
    var_table_name VARCHAR2 (50);
    var_bgn_date DATE;
    var_end_date DATE;

    BEGIN
  OPEN cur_TABLE_NAME;
  LOOP
    FETCH cur_TABLE_NAME INTO var_table_name;
    EXIT WHEN cur_TABLE_NAME%NOTFOUND;
    --testing output 
   DBMS_OUTPUT.PUT_LINE ('Table: '|| var_table_name);
    var_total_rows :=0;        
  OPEN cur_BEGIN_DATE; 
  LOOP
    FETCH cur_BEGIN_DATE INTO var_bgn_date, var_end_date;
    EXIT WHEN cur_BEGIN_DATE%NOTFOUND;
    --TESTING OUTPUT
     DBMS_OUTPUT.PUT_LINE ('DATES ARE: ' || var_bgn_date || ', ' ||var_end_date|| ' Table IS: '||var_table_name);

  --------THIS IS THE NOT WORKING STATEMENT DUE TO VARIABLES IN THE WHERE STATEMENT:

    execute immediate 'SELECT COUNT(*) FROM '||var_table_name || ' where  DTM >= '|| var_bgn_date ||' and DTM < '||var_end_date INTO var_total_rows;

   DBMS_OUTPUT.PUT_LINE (var_table_name||' '||var_bgn_date||' '||var_end_date ||' '||var_total_rows);

END LOOP;
CLOSE cur_BEGIN_DATE;
END LOOP;
CLOSE cur_TABLE_NAME;

结束;

如果我从 where 语句中删除变量(只需执行 'Select * from || var_table_name into var_total_rows; ),这是可行的。如果 where 子句中有一个静态值 - 它可以工作(但循环使用相同的日期,我需要更改日期!)。但是我不能使语法适用于 where 子句中的动态变量。 这个可以吗?

感谢您的帮助!

【问题讨论】:

这是您使用的实际代码吗?前 3 行左右充满了语法错误。 【参考方案1】:

您的 var_bgn_datevar_end_date 变量属于 DATE 类型,但作为未加引号的字符串插入到动态语句中,并具有基于会话 NLS_DATE_FORMAT 值的隐式格式。你会得到如下生成的语句:

SELECT COUNT(*) FROM table_a  where  DTM >= 2014-09-25 00:00:00 and DTM < 2014-09-26 00:00:00

您可以添加转义单引号将其转换为有效语句,但仍依赖于使用相同 NLS 设置的隐式转换:

EXECUTE immediate 'SELECT COUNT(*) FROM '||var_table_name
  || ' where  DTM >= '''|| var_bgn_date ||''' and DTM < '''||var_end_date ||''''
INTO var_total_rows;

会产生:

SELECT COUNT(*) FROM table_a where  DTM >= '2014-09-25 00:00:00' and DTM < '2014-09-26 00:00:00'

但实际上你应该使用绑定变量来避免任何与字符串的转换:

EXECUTE immediate 'SELECT COUNT(*) FROM '||var_table_name
  || ' where  DTM >= :bgn_date and DTM < :end_date'
INTO var_total_rows
USING var_bgn_date, var_end_date;

【讨论】:

亚历克斯,另一个报价会去哪里? ' where 语句之前有一个引号,但它没有关闭。 @ElenaLL - 更新了引用示例;但是您应该使用绑定变量-它更有效,对数据库缓存的压力更少,并且其他场景可以避免 SQL 注入攻击。养成一个好习惯。 Alex,我的意思是绑定变量示例中缺少引号。具有转换的那个实际上有效(是的!),但正如您所说 - 绑定变量会更有效,并且该代码缺少引号。如果你有时间 - 你能编辑一下吗?非常感谢您的帮助! @ElenaLL - 抱歉,是的,愚蠢的错字...我已经解决了这个问题

以上是关于ORACLE中EXECUTE IMMEDIATE语句中使用的where子句中需要使用动态变量的主要内容,如果未能解决你的问题,请参考以下文章

oracle 中execute immediate作用

ORACLE EXECUTE IMMEDIATE 小结

在 Oracle 中使用 Execute Immediate 将数据插入表中

mariadb 10.2.3支持oracle execute immediate语法

Oracle 的 EXECUTE IMMEDIATE 与存储过程中的 LIKE 子句

如何在此代码中正确使用 oracle EXECUTE IMMEDIATE