如何在ORACLE SQL语句中使用Date类型绑定变量?

时间:2017-09-26 05:18:24

标签: oracle plsql

我的查询中有一个循环所以我必须使用Oracle程序,但只有当我给日期硬编码时它才有用,但是我想用绑定变量来做,怎么做呢?

我的查询:

DECLARE
    TABLE_NAME VARCHAR2(100);
    SQL_STATEMENT VARCHAR2(2000);
    TOTAL_CASES NUMBER(10) := 0;
    LOOP_CASES NUMBER(10) := 0;
BEGIN

    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));

        SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID) 
        FROM ' || TABLE_NAME || '@hr WHERE ATTRIBUTE_ID = 109 

        AND OLD_VALUE IS NULL AND UPDATED_BY_SCREEN = ''CRM'' AND TRUNC(UPDATE_DATE) between TO_DATE(''15-MAY-2016'') and TO_DATE(''21-MAY-2016'')';
        EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);

END;

上面的查询给我输出但是我想使用Bind Variable作为日期参数,怎么做?

我尝试过的解决方案:

DECLARE
    TABLE_NAME VARCHAR2(100);
    SQL_STATEMENT VARCHAR2(2000);
    TOTAL_CASES NUMBER(10) := 0;
    LOOP_CASES NUMBER(10) := 0;
    START_DATE Date:= TO_CHAR(:start_dt);
    END_DATE Date := TO_CHAR(:end_dt);
BEGIN

    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));

        SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID) 
        FROM ' || TABLE_NAME || '@hr WHERE ATTRIBUTE_ID = 109 

        AND OLD_VALUE IS NULL AND UPDATED_BY_SCREEN = ''CRM'' AND TRUNC(UPDATE_DATE) between TO_DATE('||START_DATE||') and TO_DATE('||END_DATE||')';
        EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);

END;

但它显示 ORA-00907:缺少右括号

我尝试过的另一种解决方案:

DECLARE
    TABLE_NAME VARCHAR2(100);
    SQL_STATEMENT VARCHAR2(2000);
    TOTAL_CASES NUMBER(10) := 0;
    LOOP_CASES NUMBER(10) := 0;
    START_DATE Date:= TO_DATE(:start_dt,'dd-mm-yyyy');
    END_DATE Date := TO_DATE(:end_dt,'dd-mm-yyyy');
BEGIN

    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));

        SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID) 
        FROM ' || TABLE_NAME || '@hr WHERE ATTRIBUTE_ID = 109 

        AND OLD_VALUE IS NULL AND UPDATED_BY_SCREEN = ''CRM'' AND TRUNC(UPDATE_DATE) between '||START_DATE||' and'||END_DATE||'';
        EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);

END;

但是它给出错误 ORA-00905:缺少关键字

如何解决?

3 个答案:

答案 0 :(得分:1)

使用绑定变量可能有两种可能的方法。第一种方法 - 如果需要在匿名块中设置参数值:

DECLARE
    TABLE_NAME VARCHAR2(100);
    SQL_STATEMENT VARCHAR2(2000);
    TOTAL_CASES NUMBER(10) := 0;
    LOOP_CASES NUMBER(10) := 0;
    -- here you calculate values to use in dynamic SQL:
    start_date date := TO_DATE('15-MAY-2016','dd-mom-yyyy');
    end_date date := TO_DATE('21-MAY-2016','dd-mon-yyyy');
BEGIN
    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));    
        SQL_STATEMENT:=
            'SELECT COUNT(DISTINCT USR_ID) 
               FROM ' || TABLE_NAME || '@hr 
              WHERE ATTRIBUTE_ID = 109 
                AND OLD_VALUE IS NULL 
                AND UPDATED_BY_SCREEN = ''CRM'' 
                AND TRUNC(UPDATE_DATE) between :P_START and :P_END'; 
          -- there are 2 parameters above - :P_START and :P_END
        EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES 
            using start_date, end_date;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);
END;

第二种方式 - 当匿名块也必须采用参数时:

DECLARE
    TABLE_NAME VARCHAR2(100);
    SQL_STATEMENT VARCHAR2(2000);
    TOTAL_CASES NUMBER(10) := 0;
    LOOP_CASES NUMBER(10) := 0;
    -- one way is when you receive string dates:
    start_date date := TO_DATE(:P_OUTER_START_DATE,'dd-mom-yyyy');
    end_date date := TO_DATE(:P_OUTER_END_DATE,'dd-mon-yyyy');
    -- or another way if you can set parameter in date format outside:
    start_date date := :P_OUTER_START_DATE;
    end_date date := :P_OUTER_END_DATE;
BEGIN
    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));    
        SQL_STATEMENT:=
            'SELECT COUNT(DISTINCT USR_ID) 
               FROM ' || TABLE_NAME || '@hr 
              WHERE ATTRIBUTE_ID = 109 
                AND OLD_VALUE IS NULL 
                AND UPDATED_BY_SCREEN = ''CRM'' 
                AND TRUNC(UPDATE_DATE) between :P_START and :P_END'; 
          -- there are 2 parameters above - :P_START and :P_END
        EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES 
            using start_date, end_date;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);
END;

有两组参数:第一对是:P_OUTER_START_DATE:P_OUTER_END_DATE,它们是整个块的参数;第二对是:P_START:P_END,它们是内部SQL查询的参数,它在块内执行。在任何情况下,我都建议在execute immediate内使用参数。

答案 1 :(得分:0)

你可以试试这个:

DECLARE
    TABLE_NAME    varchar2(100);
    SQL_STATEMENT varchar2(2000);
    TOTAL_CASES   number(10)  := 0;
    LOOP_CASES    number(10)  := 0;
    START_DATE    date        := to_date(:start_dt,'dd-mm-yyyy');
    END_DATE      date        := to_date(:end_dt,'dd-mm-yyyy');
    v_ubs         varchar2(50):='CRM'
    v_ai          pls_integer := 109;
BEGIN
    FOR MY_ROW IN 00..99
    LOOP
        TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));
        SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID) 
                          FROM '||TABLE_NAME||'@hr 
                         WHERE ATTRIBUTE_ID = :ai 
                           AND OLD_VALUE IS NULL 
                           AND UPDATED_BY_SCREEN = :ubs 
                           AND TRUNC(UPDATE_DATE) between :START_DATE and :END_DATE ';
        EXECUTE IMMEDIATE SQL_STATEMENT using v_ai, v_ubs, START_DATE, END_DATE;
        TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);
END;

答案 2 :(得分:0)

我通过声明分配给Bind Variables的变量来获得解决方案。主要问题是它是Date类型变量,所以我需要特别注意引号。

请参阅下面的解决方案:

set serveroutput on;
set echo on;
DECLARE
   TABLE_NAME VARCHAR2(100);
   SQL_STATEMENT VARCHAR2(2000);
   TOTAL_CASES NUMBER(10) := 0;
   LOOP_CASES NUMBER(10) := 0;
   START_DATE DATE := to_date(:st_date,'DD-MM-YYYY');  
    END_DATE DATE:= to_date(:en_date,'DD-MM-YYYY'); 
BEGIN
   FOR MY_ROW IN 00..99
   LOOP
       TABLE_NAME:= 'history'||TRIM(TO_CHAR(MY_ROW,'00'));

       SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID)
FROM ' || TABLE_NAME || '@hr WHERE ATTRIBUTE_ID = 109
       AND OLD_VALUE IS NULL AND UPDATED_BY_SCREEN = ''CRM'' AND TRUNC(UPDATE_DATE) 
       between '''||START_DATE ||''' and '''||END_DATE||'''';
       EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES;
       TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
   END LOOP;
   DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);

END;
/

特别注意'中的SQL_STATEMENT

<强> ============================================ =========================

修改

  

仅使用显式转换(更好的解决方案):

SET serveroutput ON;
SET echo ON;
DECLARE
  TABLE_NAME    VARCHAR2(100);
  SQL_STATEMENT VARCHAR2(2000);
  TOTAL_CASES   NUMBER(10)   := 0;
  LOOP_CASES    NUMBER(10)   := 0;
  START_DATE    VARCHAR2(20) := TO_CHAR(:st_date);
  END_DATE      VARCHAR2(20) := TO_CHAR(:en_date);
BEGIN
  FOR MY_ROW IN 00..99
  LOOP
    TABLE_NAME   := 'history'||TRIM(TO_CHAR(MY_ROW,'00'));
    SQL_STATEMENT:='SELECT COUNT(DISTINCT USR_ID)
FROM ' || TABLE_NAME || '@hr WHERE ATTRIBUTE_ID = 109       
AND OLD_VALUE IS NULL AND UPDATED_BY_SCREEN = ''CRM'' AND TRUNC(UPDATE_DATE)        
between to_date('''||START_DATE ||''',''dd-mm-yyyy'') and to_date('''||END_DATE||''',''dd-mm-yyyy'')';
    EXECUTE IMMEDIATE SQL_STATEMENT INTO LOOP_CASES;
    TOTAL_CASES := TOTAL_CASES + LOOP_CASES;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE(TOTAL_CASES);
END;
/