Sql 接收ORA-01843:检索两个日期之间的数据时出现无效的月份错误

Sql 接收ORA-01843:检索两个日期之间的数据时出现无效的月份错误,sql,oracle,Sql,Oracle,我在oracle数据库表中有一列,它是Varchar2。在此列中,我存储日期行29-1-2021或28-12-2020。我想从下面的查询中检索两个日期之间的数据,然后我得到了无效月份的错误。我如何解决这个问题 SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail, Product_item, product_description, reque

我在oracle数据库表中有一列,它是
Varchar2
。在此列中,我存储日期行29-1-2021或28-12-2020。我想从下面的查询中检索两个日期之间的数据,然后我得到了无效月份的错误。我如何解决这个问题

SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail, 
  Product_item, product_description, request_raised_date, request_raised_time, cm.EMP_NAME as raised_by, Lse.User_Closer_Description,
  Cm1.Emp_Name as Closer_User, Lse.User_Closer_Date, Lse.Final_Closer_Description, Lse.Final_Closer_Date, Lse.Final_Closer_Time,
  Cm2.Emp_Name as Final_Closer, Lse.Resource_Effected ,
  ROUND(24*(sysdate - to_date(Request_Raised_Date
  ||' '
  ||request_raised_time, 'DD-Mon-RR HH24:MI:SS'))) AS TAT
  FROM Xx_Lsp_Linestoppage_Entry lse 
  Left join Emp_Master cm ON Lse.Raised_By = Cm.Emp_No
  Left join Emp_Master cm1 ON Lse.Closer_User = Cm1.Emp_No
  Left join Emp_Master cm2 ON Lse.Final_Closed_By = Cm2.Emp_No
  where TO_DATE(Lse.Request_Raised_Date, 'DD-Mon-RR') Between TO_DATE('01-Jan-21', 'DD-Mon-RR') and TO_DATE('29-Jan-21', 'DD-Mon-RR');

您正在以
29-1-2020(dd-mm-yyyy)
格式存储日期,因此在截止日期中使用此格式

替换

DD-Mon-RR


在转换之前,您应该检查作为字符串存储的日期值的有效性,并对其进行清理(或修复)

例如,可以通过PL/SQL块中的游标(或封装在函数中以导出查询结果或按其值进行筛选)来完成此操作:

小提琴

注意,您需要在格式中引用破折号以使其精确,因为Oracle将未引用的破折号视为来自相当广泛的分隔符集的任何符号。因此,它将把
01/12/2020
处理为
日期'2020-12-01'
,而不是无效日期

select to_date('01/12/2021', 'dd-mm-yyyy') as dt from dual;

DT                   
-------------------- 
2021-12-01T00:00:00Z 


Elapsed: 00:00:00.002
1 rows selected.

select to_date('01-12-2021', 'dd-mm-yyyy') as dt from dual;

DT                   
-------------------- 
2021-12-01T00:00:00Z 


Elapsed: 00:00:00.002
1 rows selected.

select to_date('01$12$2021', 'dd-mm-yyyy') as dt from dual;

DT                   
-------------------- 
2021-12-01T00:00:00Z 


Elapsed: 00:00:00.002
1 rows selected.

可能是类型为varchar2的Lse.Request\u Raised\u Date字段,它包含的信息比查询所需的更多。 我认为最好的方法是选择一个字符串,该字符串仅标识使用函数标识日期所需的部分:

 substr(string , string start from , string lenght )
这是一个例子:

 select to_date(substr('29-01-2021 23:01:55',1,10),'DD-MM-YYYY') from dual;

 TO_DATE (SU
 ----------
 29-01-2021

输入字段Lse.Request_Raised_Date,而不是我的字符串'29-01-2021 23:01:55'。

您可以在转换错误时使用

to_date(Request_Raised_Date || ' ' || request_raised_time 
        default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
这将返回
NULL
,而不是错误

希望这是一堂关于为什么不应将日期/时间值存储为字符串的课。实际上,您可以使用以下方法查找错误值:

select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time 
            default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
      Request_Raised_Date is not null

这可能会让您了解如何修复数据。

为什么要将日期值存储为varchar?这是个非常非常糟糕的主意。每次你这么做,一只独角兽就死了。你遇到的问题是这个错误决定的直接结果(我打赌有人说“是的,我们可以在将所有日期存储到可怕的格式之前验证它们。相信我,不会有问题”)永远不要将日期存储为文本,始终使用正确的日期列。我不明白。您在表
Xx\u Lsp\u Linestoppage\u条目中写入列
Request\u Raised\u Date
,其中包含一个表示日期的字符串,例如29-1-2021,但在[SQL]查询条件中,您使用的是不同格式的字符串,即
DD Mon RR
。你熟悉Oracle吗?也许是你的问题,然后发布你收到的整个[Oracle]错误消息。难以置信,有些人在一年中仍然使用2位数,或者我应该说“有些人再次使用2位数”?也许这是很久以前的事了,人们已经不知道了。谢谢@Popeye的回复。在截止日期(“2021年1月1日”、“yyyy年12月1日”)和截止日期(“2021年1月29日”、“yyyy年12月29日”)之间,仍收到相同的截止日期错误(Lse.Request“提出日期”dd mm yyyy);更改格式,这里还有
DD Mon RR HH24:MI:SS'
@MoinKhan列
Request\u Raised\u Date
中的值是否包含前导空格、尾随空格或嵌入空格?例如:
29-01-2021
to_date(Request_Raised_Date || ' ' || request_raised_time 
        default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time 
            default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
      Request_Raised_Date is not null