You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 04:45:04