`

ORACLE 判断字符型能否转换成日期型 ORA-01847 ORA-01843

 
阅读更多

ORACLE 判断字符型能否转换成日期型 ORA-01847 ORA-01843

判断字符型日期是否是合法的日期格式
ORA-01847 ORA-01843
有一用户的表需要导入到我们系统中,原表TM_WWM中日期是VARCHAR8)型,格式为yyyymmdd。在导入到我系统之前需要先看看日期是否合法
  • SQL1
select to_date(SALEDATE,'YYYYMMDD') from TM_WWM b
*
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month
从提示可以看到字符型的日期中有非法字符,比如00天,或230日之类的。一开始想做一个日期表,存放几十年没月的开始日期结束日期,然后把这两个表中日期字段进行比较来判断是否合法。再或者不用中间表,用小时候学到的判断大小月的方法,1357810,腊,这7个月是31天,直接写SQL比较,2月单独判断。但是这两个方法都是比较死板的,于是想到用自己和自己比较的方法,如下。
  • SQL2
select count(*) from TM_WWM
where saledate is not null
and substr(saledate,1,4) between 1970 and 2008
and substr(saledate,5,2) between '01' and '12'
and SALEDATE
between to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD')
*
ERROR at line 7:
ORA-01843: not a valid month
可以看到to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
是取得本日期所在月的第一天,比如SALEDATE20070312,则这里得到是20070301
to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD')是得到本日期下月第一天,是20070401,那么在这两个日期之间的就应该是合法日期了。
但是上面却报月份错误,于是用下面SQL判断月份到底有没问题
  • SQL3
select distinct(to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD')) from TM_WWM
where saledate is not null
and substr(saledate,1,4) between 1970 and 2008
and substr(saledate,5,2) between '01' and '12'
这个SQL没问题,说明1970年到2008年之间所有年月都没问题,可以正常格式化成日期,那就只能说明是DAY有问题了。
  • SQL4
select count(*) from
(select * from TM_WWM
where saledate is not null
and substr(saledate,1,4) between 1970 and 2008
and substr(saledate,5,2) between '01' and '12')
where SALEDATE
between to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD')
1981098 行记录
注意SQL2SQL4的区别,SQL2 是年月日的限制都在同一级,那么SQL是按照从右到左去分析执行(以前一直认为不是所有的RBO都是从右到左,所以一直都不在意,今天吃到苦头了,你也可以把先后顺序颠倒下,效果和SQL4一样),SQL4则年月在内侧,在符合年月的情况下“日期“都在本月1号到下月1号之间。到这里就能说SELECT的字符型日期都满足日期格式吗?
  • SQL4
select count(to_date(SALEDATE,'YYYYMMDD')) from (select * from (select * from TM_WWM
where saledate is not null
and substr(saledate,1,4) between 1970 and 2008
and substr(saledate,5,2) between '01' and '12')
where SALEDATE
between to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD'))
却不行
ERROR at line 1:
ORA-01839: date not valid for month specified
看到将SQL4COUNT*)改成count(to_date(SALEDATE,'YYYYMMDD')),也就是说to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')可以执行,但是to_date(SALEDATE,'YYYYMMDD')却不可以执行。仔细观察这两个语句是to_date(SUBSTR(SALEDATE,1,6),'YYYYMM')to_date(SALEDATE,'YYYYMMDD')的区别,还是前面判断的是日的问题而不是月的问题(不知为何ORACLE总体是month有问题)。也就是说如果SALEDATE20060230,那么between to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1),'YYYYMMDD'))的范围是2006020120060301,而字符型20060230也在这个范围内,所以也符合条件能被选出,而to_date(SALEDATE,'YYYYMMDD')的时候却非法了。当时之所以考虑用2006020120060301范围是因为考虑到时分秒的情况,而本例却没有时分秒,所以将范围改为
  • SQL5
select * from (select * from TM_WWM
where saledate is not null
and substr(saledate,1,4) between 1970 and 2008
and substr(saledate,5,2) between '01' and '12' )
where SALEDATE
between to_char(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),'YYYYMMDD')
AND to_char(ADD_MONTHS(to_date(SUBSTR(SALEDATE,1,6),'YYYYMM'),1)-1,'YYYYMMDD')
这个时候范围是2006020120060228,运行正常。
本例判断字符型日期是否是合法的日期格式采用自己和自己比较的方式一个SQL实现,比较灵活,可移植性也很高。
分享到:
评论

相关推荐

    go-ora:Pure Go Oracle客户端

    Go-ora 什么是新的: 版本2.15 支持更多字符集(0x33D,0x33E,0x33F,0x340、0x352、0x353、0x354) 版本2.0-beta 将客户端版本更新为317 将ttc版本更新为:9 使用4个字节的数据包长度而不是2个字节 使用高级...

    Oracle9i的init.ora参数中文说明

    Oracle9i初始化参数中文说明 Blank_trimming: 说明: 如果值为TRUE, 即使源长度比目标长度 (SQL92 兼容) 更长, 也允许分配数据。 值范围: TRUE | FALSE 默认值: FALSE serializable: 说明: 确定查询是否获取表级...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    是oracle权限最高的用户,登录时不能用normal。 2. system用户:超级用户,默认是SYSOPT(操作数据库的人),不过它也能以SYSDBA的权限登陆。拥有普通dba角色权限。 3. scott用户:是个演示用户,是让你学习Oracle用的...

    Oracle 数据类型

    5、DATE数据类型,使用7个字节固定长度,每个字节分别存储世纪,年,月,日 ,时,分,秒,ORACLE中SYSDATE函数的功能是返回当前的日期和时间 6、TIMESTAMP数据类型,和DATE相似,但是这个类型的秒精确到小数点后6...

    oracle实验报告

    在命令的where子句中给出1=2,表示条件不可能成立,因而只能复制表结构,而不能复制任何数据到新表中去。另外,还可以复制一个表的部分列定义或部分列定义及其数据。 三、 Oracle数据库数据查询 1、单表查询 2、多...

    最全的oracle常用命令大全.txt

    当不能关闭数据库时,可以用startup force来完成数据库的关闭 先关闭数据库,再执行正常启动数据库命令 7、startup pfile=参数文件名 带初始化参数文件的启动方式 先读取参数文件,再按参数文件中的设置启动数据库...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    有近20年使用Oracle技术产品以及Oracle数据库管理员/Oracle数据库应用管理员的经验,是真正应用集群、性能调优以及数据库内部属性方面的专家。同时是一位演讲家及Oracle ACE。  JARED STILL 从1994年就开始使用...

    ORACLE9i_优化设计与系统调整

    §3.2.7 不能在参数文件中指定的参数 70 §3.2.8 当参数指定错误时怎么办? 70 §3.3 参数内容说明 70 §3.4 DBA常用参数说明 71 §3.4.1 跟踪文件路径(BACKGROUND_DUMP_DEST) 71 §3.4.2 在缓冲区驻留对象...

    oracle数据库笔记

    (1)字符型 26 (2)数值型 26 (3)日期时间型 26 (4)LOB (大型对象) 26 (5)RowID (伪列类型) 27 2. 创建表 27 (1)Create Table 表名 27 (2)在原来已有表上建一个新表(结构和数据) 27 (3)使用OEM...

    Oracle 10g 开发与管理

    (1)字符型 26 (2)数值型 26 (3)日期时间型 26 (4)LOB (大型对象) 26 (5)RowID (伪列类型) 27 2. 创建表 27 (1)Create Table 表名 27 (2)在原来已有表上建一个新表(结构和数据) 27 (3)使用OEM...

    操作Oracle的php类

    用】: Oracle公用函数类 // 【作 者】: 天灰 // // 【最后修改日期】: 2001/05/11[cxx] // 【变量定义规则】:‘C_’=字符型,‘I_’=整型,‘N_’=数字型,‘L_’=布尔型,‘A_’=数组型 //

    orcale常用命令

    当不能关闭数据库时,可以用startup force来完成数据库的关闭 先关闭数据库,再执行正常启动数据库命令 7、startup pfile=参数文件名 带初始化参数文件的启动方式 先读取参数文件,再按参数文件中的设置启动数据库...

    2009达内SQL学习笔记

    rollback:回溯,回溯到上次操作前的状态,把这次事务操作作废,只有一次(DDL和DCL语句会自动提交,不能回溯)。 可以用commit语句提交,这样就回溯不回了。 set pause on\off :设置分屏(设置不分屏) set pause...

    jdbc基础和参考

    many-to-one:标签中对于cascade的取值delete,delete-orphan,all-delete-orphan(只用unique属性值不为true不能出现)慎用 cascade:级联属性 none:不做任何级联操作 save-update:对当前对象执行save,update, ...

    Toad 使用快速入门

    各种错误处理模块可供参考,各类字符日期函数 包含1400多个主题 Admin: 解答DBA日常工作中80%的常见问题,覆盖2400多个主题 从网络到性能优化,从备份恢复到Error message,一应俱全 例子:遇到失效的存储...

Global site tag (gtag.js) - Google Analytics