如何识别存储在Oracle DATE列中的无效(损坏)值

时间:2012-01-04 21:48:35

标签: sql oracle date oracle10g

Oracle 10.2.0.5

在DATE列中标识表中具有“无效”值的行的最简单方法是什么。这里的“无效”是指我的意思是违反Oracle日期值规则的二进制表示。

我最近遇到了一个存储在列中的无效日期的问题。

我能够使用查询谓词来查找特定的有问题的行:

  WHERE TO_CHAR(date_expr,'YYYYMMDDHH24MISS') = '00000000000000'

在我遇到的情况下,世纪字节无效......

 select dump(h.bid_close_date) from mytable h where h.id = 54321

 Typ=12 Len=7: 220,111,11,2,1,1,1

世纪字节应为100 +两位数世纪。在这种情况下,增加了额外的100,好像世纪价值是“120”,使得年份“12011”。 (我知道在数据库中获取无效DATE值的唯一方法是使用OCI,使用本机7字节DATE表示。)

在这种情况下,TO_CHAR函数返回一个可识别的字符串,我可以用它来识别不稳定的DATE值。

我的问题:是否有更通用或更简单的方法(最好使用SQL SELECT语句)来识别DATE列中“无效”值的行。

5 个答案:

答案 0 :(得分:6)

这是一个非常不寻常的场景(虽然我之前遇到过类似的事情)。更常见的问题是找到在日期列中作为字符串保存的无效日期。您可以通过构建自己的日期验证器来使解决方案适应您的情况。

这样的事情:

create or replace function is_a_date 
    ( p_date in date )
    return varchar2
is
    d date;
begin
    d := to_date(to_char(p_date,  'SYYYYMMDDHH24MISS'),  'SYYYYMMDDHH24MISS') ;
    if d != p_date then
        return 'not a proper date';
    else
        return 'good date';
    end if;
exception
    when others  then
        return 'not a date';
end;
/ 

这会将日期转换为字符串,然后再转回。它捕获由日期转换引发的异常。如果最终产品与输入日期不同,那么可能在翻译中丢失了一些东西;说实话,我不确定12011日期是否会成功投射到一个字符串,所以这是一个带状的方法。在没有一些测试数据的情况下编写这个实用程序有点棘手!

此查询将识别所有无效日期:

 select h.id, dump(h.bid_close_date)
 from mytable h 
 where h.bid_close_date is not null
 and is_a_date(h.bid_close_date) != 'good date';

答案 1 :(得分:3)

不添加函数,简单的谓词

TO_CHAR(date_col,'YYYYMMDDHH24MISS') = '000000000000'

似乎可以识别存储在Oracle DATE列中的损坏值。添加功能似乎是不必要的。检查损坏的日期应该能够在SQL SELECT语句中完成,并且不要求用户对数据库具有CREATE FUNCTION特权。

答案 2 :(得分:2)

这标识无效月份

SELECT rowid,
       pk_column,
       DUMP(date_column, 1010) AS dump1
FROM   table
WHERE  TO_NUMBER(SUBSTR(DUMP(date_column, 1010), INSTR(DUMP( date_column, 1010),
                                              ',', 1, 2
                                                     ) + 1,
                                  INSTR(DUMP(date_column, 1010), ',', 1, 3) - (
                                  INSTR(DUMP( date_column, 1010), ',', 1, 2) + 1
                                  ))) = 0; 

使用相同的where子句更新,我发现在这些情况下月份数为零。

答案 3 :(得分:0)

我想找一个可以作为检查约束实现的方法,可能是通过检查日期是否在合法值的范围内。

但是,问问自己,日期为1066-10-14是否有效?这是一个合法的价值,但您可能没有在当天打印发票,例如。因此,您可能希望将无效日期检查转换为您在应用程序上下文中认为有效的更大问题。

答案 4 :(得分:0)

我有一个SQL Error: ORA-01841: (full) year must be between -4713 and +9999, and not be 0 01841. 00000 - "(full) year must be between -4713 and +9999, and not be 0"

因此,为了确定日期错误的行,我执行了以下操作。

declare
    cursor mydates is select table_pk, your_date_col from table;
    c_date table.your_date_col%type;
    c_pk table.table_pk%type;
    testrow table.your_date_col%type;
begin
    open mydates;
    loop
    begin
        fetch mydates into c_pk, c_date;
        exit when mydates%notfound;
        testrow := TO_TIMESTAMP(c_date,'YYYY-MM-DD HH24:MI:SS');
    exception when others then
        dbms_output.put_line('bad file: ' || c_pk);
    end;
    end loop;
    close mydates;
end;

所以我要做的就是创建一个游标,遍历元素并测试每个元素并显示标识符,这样我就可以轻松找到坏行。