如何处理SELECT语句中的to_date异常以忽略这些行?

nts*_*sue 8 oracle crystal-reports

我有以下查询,我试图在我正在处理的水晶报表中用作COMMAND.

SELECT * FROM myTable
WHERE to_date(myTable.sdate, 'MM/dd/yyyy') <= {?EndDate}
Run Code Online (Sandbox Code Playgroud)

这很好用,但我唯一担心的是日期可能并不总是格式正确(由于用户错误).我知道当to_date函数失败时会抛出异常..是否有可能以忽略SELECT语句中相应行的方式处理此异常?因为如果整个数据库中只有一个日期格式不正确,我的报告就会中断.

我查看Oracle是否提供了isDate函数,但看起来您应该只处理异常.任何帮助将不胜感激.谢谢!!

Jus*_*ave 25

回应Tony的评论,你最好不要在DATE列中存储日期,而不是强迫前端查询工具查找和处理这些异常.

但是,如果您遇到错误的数据模型,最简单的选择是创建一个执行转换并处理错误的函数,

CREATE OR REPLACE FUNCTION my_to_date( p_date_str IN VARCHAR2,
                              p_format_mask IN VARCHAR2 )
  RETURN DATE
IS
  l_date DATE;
BEGIN
  l_date := to_date( p_date_str, p_format_mask );
  RETURN l_date;
EXCEPTION
  WHEN others THEN
    RETURN null;
END my_to_date;
Run Code Online (Sandbox Code Playgroud)

您的查询将成为

SELECT * 
  FROM myTable
 WHERE my_to_date(myTable.sdate, 'MM/dd/yyyy') <= {?EndDate}
Run Code Online (Sandbox Code Playgroud)

当然,您最有可能想要在MY_TO_DATE调用上使用基于函数的索引,以使此查询合理有效.

  • +1 Legacy系统是生活中的事实.我们必须尽力处理它们. (11认同)

Joh*_*ock 5

如果您的数据不一致且存储为字符串的日期可能无效,那么您有3个选项.

  1. 重构数据库以确保该列存储日期数据类型
  2. 处理存储过程中迄今为止的字符串异常
  3. 在(复杂)记录选择公式中处理迄今为止的字符串异常

我建议使用第一个选项,因为您的数据应该是一致的.

第二个选项将提供一些灵活性和速度,因为报告只会获取所需的行.

第三个选项将强制报告获取表中的每个记录,然后让报告过滤掉记录.


Mic*_*ten 5

我也有同样的问题...一个旧的遗留数据库,其中包含日期的 varchar 字段和该字段中数十年的错误数据。尽管我很愿意,但我也无法更改数据类型。但我想出了这个解决方案来查找日期是否是最新的,这似乎也是您正在做的事情:

select * from MyTable
where regexp_like(sdate, '[0-1][0-9].[0-3][0-9].[0-9][0-9][0-9][0-9]')
         -- make sure it's in the right format and ignore rows that are not
and substr(sdate,7,10) || substr(sdate,1,2) || substr(sdate,4,5) >= to_char({?EndDate}, 'YYYYMMDD')
         -- put the date in ISO format and do a string compare
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是不会因为“2 月 30 日”这样的日期而感到窒息。


Mar*_*ber 5

从 Oracle 12c 开始,无需定义函数来捕获转换异常。

Oracle在函数ON CONVERSION ERROR中引入了一个子句TO_DATE

基本上,该子句会抑制无效日期字符串转换中的错误(典型错误是ORA-01843, ORA-01841, ORA-011861, ORA-01840)并返回指定的默认值或 null。

使用示例

select to_date('2020-99-01','yyyy-mm-dd') from dual;
-- ORA-01843: not a valid month
select to_date('2020-99-01' default null on conversion error,'yyyy-mm-dd') from dual;
-- returns NULL
select to_date('2020-99-01' default '2020-01-01' on conversion error,'yyyy-mm-dd') from dual;
-- 01.01.2020 00:00:00
Run Code Online (Sandbox Code Playgroud)

遗留应用程序的解决方案

假设有一个表,其中日期列存储为 VARCHAR2(10)

select  * from tab;

DATE_CHAR 
----------
2021-01-01
2021-99-01
Run Code Online (Sandbox Code Playgroud)

使用上述功能VIRTUAL定义了 DATE 列,该列要么显示日期,要么NULL显示转换错误

alter table tab add (
  date_d DATE as (to_date(date_char default null on conversion error,'yyyy-mm-dd')) VIRTUAL
);

select * from tab;

DATE_CHAR  DATE_D             
---------- -------------------
2021-01-01 01.01.2021 00:00:00
2021-99-01  
Run Code Online (Sandbox Code Playgroud)

VIRTUAL列可以安全使用,因为它的格式是DATE,如果需要,可以在其上设置索引。

 select  * from tab where date_d = date'2021-01-01';
Run Code Online (Sandbox Code Playgroud)