如何修复 ORA-01843:不是有效月份?

How do I fix ORA-01843: not a valid month?

所以在查询级别,我有:

to_char(
    (
        to_date(
        substr(TIMESTAMP, 1, 19),
        'yyyy-mm-dd hh24:mi:ss'
        )
    ),
    'dd-mon-yyyy hh24:mi:ss'
    ) as DateTime,

我已经尝试查看几篇文章,其中一篇最著名:

How to change the date format in Oracle BI Publisher?

我也试过使用:

and trunc(TIMESTAMP) between :FROM_DATE AND :TO_DATE
--and also
and trunc(TIMESTAMP) between to_date(:FROM_DATE, 'yyyy-MM-dd') AND to_date(:TO_DATE, 'yyyy-MM-dd')

在检查结构和 XML 时,我注意到我的日期是字符串格式:

element name="DATETIME" value="DATETIME" label="DATETIME" dataType="xsd:string" breakOrder="ascending" fieldOrder="3"

所以我删除了 to_char 以获得日期格式

我得到的错误是:

java.sql.SQLDataException: ORA-01843: not a valid month

我该如何解决这个问题?

编辑: TIMESTAMP 列的格式,格式为 CHAR(14) 值的示例类似于 20200701103038 它在 SQL Developer

中完美运行

只是为了确定 SYSDATE(我要 select)代表什么:

SQL> alter session set nls_Date_format = 'dd.mm.yyyy';

Session altered.

今天是:

SQL> select sysdate from dual;

SYSDATE
----------
26.07.2020

这是获取错误的方法:将错误的格式掩码应用到表示 DATE 值的字符串:

SQL> select to_Date('2020-27-07', 'yyyy-mm-dd') from dual;
select to_Date('2020-27-07', 'yyyy-mm-dd') from dual
               *
ERROR at line 1:
ORA-01843: not a valid month


SQL>

如何解决?通常,如果日期表示为字符串,则很难修复它。它们(代表日期的字符串)就像一盒巧克力,你永远不知道你会得到什么。如果至少有一个错误值,查询将失败。

如何找到错误的值?如果传递给它的字符串表示有效的日期格式,则可以创建一个 returns TRUE(或 1 或任何你想要的)函数。但是,如果你传递 01/02/03,哪个是哪个?不同的格式匹配(例如 dd/mm/yyyy/mm/ddmm/yy/dd ...)。更糟糕的情况是 84/25/32AB/23/2f。它们都是字符串,它们“匹配”两个由斜杠分隔的字符,但肯定不是有效日期,因此您不能依赖简单的正则表达式。

很快,没有简单快捷的方法。

好吧,使用 varchar2 或 char 将 DATES 存储为字符串是一种非常糟糕且扩展的做法。无论如何,话虽如此,我认为您的设置或构建查询的方式有问题:

SQL> alter session set nls_date_format='YYYYMMDDHH24MISS' ;

Session altered.

SQL> select to_date('20200726123722') from dual ;

TO_DATE('20200
--------------
20200726123722

SQL> select sysdate from dual ;

SYSDATE
--------------
20200726124622

此外,如您所说,如果您的数据存储为 YYYYMMDDHHMISS,则您对该字符应用了错误的日期掩码 YYYY-MM-DD HH24:MI:SS。我会使用 CAST 将字段定义为 DATE。

例子

SQL> create table my_test ( c1 char(20) ) ;

Table created.

SQL> insert into my_test values ('20200726123722') ;

1 row created.

SQL>  insert into my_test values ('20200725123722') ;

1 row created.

SQL> commit ;

Commit complete.

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

Session altered.

SQL> select cast(c1 as date) from my_test ;

CAST(C1ASDATE)
-------------------
2020-07-26 12:37:22
2020-07-25 12:37:22

SQL>

更新

如果您无法更改 NLS 会话设置,则必须对结果输出应用 TO_CHAR。但是在你的情况下,你想要操作日期,所以只要它是你想要操作的日期值,你就可以忘记掩码。

SQL> col value for a20
SQL> select value from nls_database_parameters where parameter = 'NLS_DATE_FORMAT' ;

VALUE
--------------------
DD-MON-RR

SQL> select cast(to_date('20200725123722','YYYYMMDDHH24MISS') as date) from dual ;

CAST(TO_D
---------
25-JUL-20

SQL> select to_char( cast(to_date('20200725123722','YYYYMMDDHH24MISS') as date) , 'YYYYMMDDHHMISS' ) from dual ;

TO_CHAR(CAST(T
--------------
20200725123722

SQL> select case when cast(to_date('20200725123722','YYYYMMDDHH24MISS') as date)  > sysdate
  2  then 'FALSE'
  3  else
  4  'TRUE'
  5  end as result from dual ;

RESUL
-----
TRUE

SQL>

因此,如果您想将日期与另一个日期进行比较,请不要使用 to_char。如果您想以特定格式显示值,当您没有更改设置的选项时,请使用 to_char.