【问题标题】:Find out what data caused an Oracle error找出导致 Oracle 错误的数据
【发布时间】:2016-12-15 17:53:23
【问题描述】:

我正在尝试在 SQL Developer 中运行 select 语句,该语句将 20160809 之类的字段转换为 date。我的查询看起来像:

select
  to_date(sale_date, 'YYYYMMDD') as sale_date
from properties

这是在抛出ORA-01839: date not valid for month specified。我已经尝试了从子字符串到正则表达式的所有方法,试图推断出哪个值导致了错误,但没有骰子。有什么方法可以执行此查询并获取to_date 的输入导致它失败?

【问题讨论】:

  • sale_date 列的类型是什么?你那里有任何无效的日期,例如8 月 32 日?
  • @TimBiegeleisen:这是一个varchar2 字段。我不确定是否有无效日期。希望看到to_date 的输入破坏了它。
  • 我会从select to_date from properties where length(to_date) != 8开始。先排除这些。如果在另一个时代,日期以数字形式保存,后来又转换为字符串,那可能会引入各种错误。

标签: sql oracle plsql oracle11g


【解决方案1】:

设置:

create table properties(sale_date varchar2(8));
insert into properties values ('20160228');
insert into properties values ('20160230'); 
insert into properties values ('xxxx');

如果你的桌子不是太大,你可以试试这个:

SQL> declare
  2      d date;
  3  begin
  4      for i in (select * from properties) loop
  5          begin
  6              d:= to_date(i.sale_date, 'yyyymmdd');
  7          exception
  8              when others then
  9                  dbms_output.put_line('KO: "' || i.sale_date || '"');
 10          end;
 11      end loop;
 12  end;
 13  /
KO: "20160230"
KO: "xxxx"

PL/SQL procedure successfully completed.

【讨论】:

【解决方案2】:

我认为您可能需要一种蛮力方法:

select sale_date
from properties 
where substr(sale_date, 5, 4) not between '0101' and '0131' and
      substr(sale_date, 5, 4) not between '0201' and '0228' and
      substr(sale_date, 5, 4) not between '0301' and '0431' and
      substr(sale_date, 5, 4) not between '0401' and '0430' and
      substr(sale_date, 5, 4) not between '0501' and '0531' and
      substr(sale_date, 5, 4) not between '0601' and '0630' and
      substr(sale_date, 5, 4) not between '0701' and '0731' and
      substr(sale_date, 5, 4) not between '0801' and '0831' and
      substr(sale_date, 5, 4) not between '0901' and '0930' and
      substr(sale_date, 5, 4) not between '1001' and '1031' and
      substr(sale_date, 5, 4) not between '1101' and '1130' and
      substr(sale_date, 5, 4) not between '1201' and '1231';

这不是 100% 完美的。它留下了闰年错误的可能性。您可以使用以下方法手动调查:

select sale_date
from properties 
where sales_date like '%0229';

【讨论】:

  • 有两个无效的闰年日期!这很有帮助,谢谢。
【解决方案3】:

您使用的是 Oracle 12c 吗?如果是的话,那么

with function safe_to_date(p_string VARCHAR2, p_format VARCHAR2) RETURN DATE IS
BEGIN 
  return to_date(p_string, p_format);
EXCEPTION
  WHEN others THEN
    return NULL;
END;
select sale_date from properties
where sale_date is not null and safe_to_date(sale_date,'YYYYMMDD') IS NULL ;

如果您不在 Oracle 12c 上,您可以将 safe_to_date 放入一个包中,说“my_pkg”,然后:

select sale_date from properties
where sale_date is not null and my_pkg.safe_to_date(sale_date ,'YYYYMMDD') IS NULL ;

【讨论】:

  • 我使用的是 11g,但我会考虑将其放入一个包中。谢谢!
猜你喜欢
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-01
  • 2018-01-03
  • 1970-01-01
  • 2015-09-11
  • 2011-06-28
相关资源
最近更新 更多