PL/SQL块执行报ORA-01861字面量与格式字符串不匹配错误求助
PL/SQL报错ORA-01861问题排查与解决
错误原因
- 核心原因是动态SQL中存在数据类型不匹配导致的隐式转换错误:你在WHERE条件中写了
TO_CHAR(datetime, '||T||') BETWEEN to_date('||B||','||T||') AND to_date('||A||','||T||'),左边TO_CHAR的返回值是字符串类型,右边to_date的返回值是DATE类型,Oracle会自动将左边的字符串隐式转换为DATE类型,转换时默认使用会话的日期格式参数,和你定义的T格式串YYYY/MM/DD HH24:MI:SS不匹配,因此触发ORA-01861: 字面量与格式字符串不匹配错误。 - 次要问题:动态SQL拼接方式容易出现引号匹配错误,也存在SQL注入风险,同时你SELECT的COUNT(1)没有显式指定别名,后续扩展容易出现字段对应错误。
- 额外业务逻辑隐患:变量B的赋值逻辑为取昨天所在年月拼接23号,如果昨天的日期小于当月23号,会出现B的日期大于A的日期的情况,导致BETWEEN条件无匹配数据。
解决方法
方法1:修正条件类型不匹配问题(快速修复)
将WHERE条件改为两边都为DATE类型,无需转换为字符串,修改后的动态SQL条件部分如下:
WHERE datetime BETWEEN to_date('||B||','||T||') AND to_date('||A||','||T||') AND TO_CHAR(datetime, '||D||') BETWEEN ('||E||') AND ('||F||')
方法2:改用绑定变量重构(推荐)
完全避免动态拼接参数,消除引号匹配和隐式转换风险,性能更优,修改后的代码核心部分如下:
DECLARE -- 去掉多余的嵌套引号,绑定变量不需要额外转义引号 D VARCHAR2(20):='HH24:MI:SS'; G VARCHAR2(20):='MM'; E VARCHAR2(20):='06:00:00'; F VARCHAR2(20):='23:59:59'; T VARCHAR2(200):='YYYY/MM/DD HH24:MI:SS'; -- 直接定义为DATE类型,不需要存储带引号的字符串 A DATE; B DATE; L_BODY CLOB; TYPE resp_time IS RECORD ( servis varchar2(200), operasyon varchar2(200), total varchar2(200), avg_brt varchar2(200), month_ varchar2(200) ); TYPE resp_time2 IS TABLE OF resp_time INDEX BY PLS_INTEGER; resp_time3 resp_time2; TYPE l_cursor is REF CURSOR; c l_cursor; BEGIN -- 直接赋值DATE类型,不需要转字符串加引号 SELECT trunc(sysdate-1) into A FROM dual; SELECT to_date(to_char(trunc(sysdate-1),'YYYY/MM')||'/23 00:00:00', T) into B FROM dual; -- 动态SQL用占位符,通过USING传参,避免拼接风险 OPEN C FOR 'SELECT * FROM ( SELECT service as servis, CASE WHEN operation is null THEN ''operasyon_yok'' ELSE operation END operasyon, COUNT (1) as total, ROUND (AVG (brt)) avg_brt, to_char(datetime, :G) as month_ FROM SERVICELOG WHERE datetime BETWEEN :B AND :A AND TO_CHAR(datetime, :D) BETWEEN :E AND :F GROUP BY service, operation, to_char(datetime, :G)) WHERE avg_brt >= 3000' USING G, B, A, D, E, F, G; FETCH C BULK COLLECT INTO resp_time3; CLOSE C; -- 后续拼接HTML逻辑不变
内容的提问来源于stack exchange,提问作者Emrahall
相关产品推荐
相关产品推荐

