Oracle01877,ORA-01877: string is too long for internal buffer 排查

博客内容讲述了在Oracle数据库中遇到的一个错误,即ora-1877,原因是日期字段被错误地转换为字符串进行比较。通过逐步排查,发现问题在于日期字段包含了公元前的异常值,导致查询失败。修复后的SQL语句将日期直接转换为日期类型进行比较,解决了问题。此外,还探讨了Oracle对于时间戳的存储范围,指出公元前9500多年的值是如何出现的,并通过示例展示了Oracle对时间戳的合法范围。
摘要由CSDN通过智能技术生成

今天开发说有个程序,页面查询报ora-1877错误,提供了sql那是个页面展示的语句,为了直观缩短处理后如下

SELECT COUNT (*)

FROM (SELECT a.icpcode, a.discomname

FROM ehealth_arch_basicinfo a

WHERE TO_CHAR (a.BUILD_DATE, 'yyyy-mm-dd') >= '1900-01-01'

AND TO_CHAR (a.BUILD_DATE, 'yyyy-mm-dd') <= '2011-11-11'

AND (a.ext_field1 IS NULL OR a.ext_field1 = '0')) b,

node_center_region c

WHERE c.cityid = 220800 AND b.icpcode = c.nodeid;

ORA-01877: string is too long for internal buffer

sql问题排查,当然一步步拆分,先去掉时间限制

SELECT COUNT (*)

FROM (SELECT a.icpcode, a.discomname

FROM ehealth_arch_basicinfo a

WHERE (a.ext_field1 IS NULL OR a.ext_field1 = '0')) b,

node_center_region c

WHERE c.cityid = 220800 AND b.icpcode = c.nodeid

发现运行成功了,那问题就在日期

发现这脚本很不正规,时间不知为什么转换成char再做比较,修改后如下

SELECT COUNT (*)

FROM (SELECT a.icpcode, a.discomname

FROM ehealth_arch_basicinfo a

WHERE a.BUILD_DATE >= TO_DATE ('1900-01-01', 'yyyy-mm-dd')

AND a.BUILD_DATE <= TO_DATE ('2011-11-11', 'yyyy-mm-dd')

AND (a.ext_field1 IS NULL OR a.ext_field1 = '0')) b,

node_center_region c

WHERE c.cityid = 220800 AND b.icpcode = c.nodeid

运行后成功

总共返回738961行

但是开发的提出,说同样的sql程序在另外两套系统上运行不存在问题,而且也是同一个实例不同schema,排除服务器设置,很是怀疑这里个里面的数据才把上面sql的隐藏很久的bug给暴露出来

那先看一下最大时间与最少时间,在toad 中执行

select max(BUILD_DATE),min(BUILD_DATE) from ehealth_arch_basicinfo

最大时间列显示为空,最小居然显示9589-11-11 0:00:00.000000

在sqlplusw 里执行

SQL> col maxdate for a35

SQL> col mindate for a35

SQL> select max(BUILD_DATE) maxdate ,min(BUILD_DATE) mindate from jmjk_jilin_th_mhk.ehealth_arch_basicinfo;

MAXDATE MINDATE

----------------------------------- -----------------------------------

10-NOV-00 12.00.00.000000 AM 11-NOV-89 12.00.00.000000 AM

SQL> alter session set NLS_TIMESTAMP_FORMAT='yyyy-mm-dd hh24:mi:ss';

会话已更改。

SQL> select BUILD_DATe,rowid r , TO_CHAR (BUILD_DATE, 'yyyy-mm-dd'),to_char(BUILD_DATe,'SYEAR')

from jmjk_jilin_th_mhk.ehealth_arch_basicinfo a where a.BUILD_DATeselect BUILD_DATE,dump(build_date) from jmjk_jilin_th_mhk.ehealth_arch_basicinfo where BUILD_DATe>sysdate

2 ;

BUILD_DATE

------------------------------

DUMP(BUILD_DATE)

------------------------------------------------------------------------------------------------------------------------------------------------------

08-DEC-11 12.00.00.000000 AM

Typ=180 Len=7: 120,111,12,8,1,1,1

10-NOV-00 12.00.00.000000 AM

Typ=180 Len=7: 211,100,11,10,1,1,1

SQL> alter session set NLS_TIMESTAMP_FORMAT='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select BUILD_DATE,dump(build_date) from jmjk_jilin_th_mhk.ehealth_arch_basicinfo where BUILD_DATe>sysdate

2 ;

ERROR:

ORA-01877: string is too long for internal buffer

退出再进

SQL> l

1 select BUILD_DATE,dump(build_date) value,rowid r,BUILD_DATE-sysdate diffdays from jmjk_jilin_th_mhk.ehealth_arch_basicinfo where BUILD_DATe>sysdate

2*

SQL> /

BUILD_DATE VALUE R DIFFDAYS

----------------------------------- -------------------------------------------------- -------------------- --------------------

08-DEC-11 12.00.00.000000 AM Typ=180 Len=7: 120,111,12,8,1,1,1 AAAeLZAAGAAA2RsAAM +000000026 10:20:42.

000000

10-NOV-00 12.00.00.000000 AM Typ=180 Len=7: 211,100,11,10,1,1,1 AAAeLZAAFAAAP9rAAJ +003319687 10:20:42.

我们计算一下,比今天晚3319687天 000000

SQL> select 3319687/365 from dual;

3319687/365

-----------

9095.03288

就是当前2011年的9095年后,这就是引起上面问题的罪魁祸首(后来把开发的sql,加上rowid排除这一行显示正常),那oracle允许yyyy存这么大的值么?

下面我们制造个错,来给出上面的答案

SQL> select to_timestamp('9999-1-1','yyyy-mm-dd')+366 from dual;

select to_timestamp('9999-1-1','yyyy-mm-dd')+366 from dual

*

ERROR at line 1:

ORA-01841: (full) year must be between -4713 and +9999, and not be 0

SQL> select to_timestamp('0001-1-1','yyyy-mm-dd')-366*5000 from dual;

select to_timestamp('0001-1-1','yyyy-mm-dd')-366*5000 from dual

*

ERROR at line 1:

ORA-01841: (full) year must be between -4713 and +9999, and not be 0

SQL> select to_timestamp('0001-1-1','yyyy-mm-dd')-366*4000 from dual;

TO_TIMESTAMP('0001-

-------------------

4008-10-15 00:00:00

呵呵,如果时间最小是-4713 ,那我们上面的公元前9500多年是怎么进去的呢?

打赏

8732971891f4ba05583674ca6b8145ac.png微信扫一扫,打赏作者吧~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值