首页 > 解决方案 > ORA-01843: 在使用 Select 语句时,月份无效

问题描述

我有三个表以下是表的表描述

SQL> DESC DRIVERS12


Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------

 D_ID                                      NOT NULL VARCHAR2(30)
 DNAME                                              VARCHAR2(30)
 AGE                                                VARCHAR2(30)
 CITY                                               VARCHAR2(30)

SQL> DESC CARS12
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------

 C_ID                                      NOT NULL VARCHAR2(30)
 COMAPNY                                            VARCHAR2(30)
 MODEL                                              VARCHAR2(30)
 PURCHASE_DATE                                      DATE

SQL> DESC RESERVES12
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------

 D_ID                                      NOT NULL VARCHAR2(30)
 C_ID                                      NOT NULL VARCHAR2(30)
 DAY                                                VARCHAR2(10)

我使用以下语法在每个表中获取数据:

 SQL> INSERT INTO DRIVERS12 VALUES(‘&D_ID’,’&DNAME’,’&AGE’,’&CITY’);
Enter value for d_id: D1
Enter value for dname: P.RAI
Enter value for age: 22
Enter value for city: BENARAS
old   2: VALUES('&D_ID','&DNAME','&AGE','&CITY')
new   2: VALUES('D1','P.RAI','22','BENARAS')

1 row created.

SQL> INSERT INTO CARS12
  2  VALUES('&C_ID','&COMPANY','&MODEL',TO_DATE('&PURCHASE_DATE','DD/MM/YY'));
Enter value for c_id: C1
Enter value for company: ROYAL ENFIELD
Enter value for model: BULLET350
Enter value for purchase_date: 02/10/16
old   2: VALUES('&C_ID','&COMPANY','&MODEL',TO_DATE('&PURCHASE_DATE','DD/MM/YY')
)
new   2: VALUES('C1','ROYAL ENFIELD','BULLET350',TO_DATE('02/10/16','DD/MM/YY'))


1 row created.

SQL> INSERT INTO RESERVES12
  2  VALUES('&D_DI','&C_ID','&DAY');
Enter value for d_di: D1
Enter value for c_id: C1
Enter value for day: MONDAY
old   2: VALUES('&D_DI','&C_ID','&DAY')
new   2: VALUES('D1','C1','MONDAY')

1 row created.

当我尝试运行以下查询时

SQL> SELECT C.MODEL,C.COMAPNY,D.CITY
  2  FROM DRIVERS12 D, CARS12 C, RESERVES12 R
  3  WHERE R.D_ID=D.D_ID AND R.C_ID=C.C_ID AND D.DNAME='M.GUHA' AND C.PURCHASE_DATE>'01/01/15';
                                                                                 *

我在第 3 行收到此错误

ERROR at line 3:
ORA-01843: not a valid month

我正在使用 Oracle 10g,谁能告诉我哪里出错了?

标签: sqloracledatetime

解决方案


正如您已经意识到问题出在这部分:

C.PURCHASE_DATE>'01/01/15'

但是您的解决方法不太正确...

这是我的错误,当我输入“02/10/16”作为输入时,它被转换为“02-OCT-16”格式。

您的PURCHASE_DATE列是DATE应有的,并且日期没有固有的人类可读格式 - Oracle 以其自己的内部表示形式存储它。当您查询它时,它会被您的应用程序或客户端转换为可读格式,通常使用您的会话NLS_DATE_FORMAT设置 - 在您的情况下,它必须DD-MON-RR来自您在查询表时获得的输出。您可以通过调用以任何您想要的格式显示它TO_CHAR(),但应将其保留为所有处理的日期。

问题是您将该日期值与字符串进行比较。Oracle 尝试将该字符串隐式转换为 date,并且由于该字符串与您的 NLS 设置不匹配,因此它无法匹配,并引发该错误 - 就像您使用相同的格式模型进行显式转换一样:

select to_date('01/01/2015', 'DD-MON-RR') from dual;

ORA-01843: not a valid month

在您的回答中,您仍在这样做:

C.PURCHASE_DATE>'01-JAN-15'

但是现在该字符串确实与您的默认格式模型匹配,因此隐式转换现在可以工作,相当于显式to_date('01-JAN-15', 'DD-MON-RR').

但是您不应依赖隐式转换或假设有关 NLS 设置的任何内容。如果在使用不同语言(因为它依赖于JAN英语月份缩写)或不同NLS_DATE_FORMAT设置的会话中运行相同的查询,则会出错。由于您的列是日期,因此您也应该使用更安全的格式模型将其与日期进行显式比较(尽管这仍然允许日期和月份数字之间存在歧义):

C.PURCHASE_DATE > TO_DATE('01/01/15', 'DD/MM/RR')

或者最好使用 4 位数年份:

C.PURCHASE_DATE > TO_DATE('01/01/2015', 'DD/MM/YYYY')

并且使用固定值,您还可以使用明确的ANSI 日期文字

C.PURCHASE_DATE > DATE '2015-01-01'

另一项观察是,您正在查找该日期午夜之后的记录。你可能真的想包括在午夜发生的任何事情:

C.PURCHASE_DATE >= DATE '2015-01-01'

推荐阅读