我的查询中有一个循环所以我必须使用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:缺少关键字
如何解决?
答案 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;
/