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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8734540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 13:50:27  来源:igfitidea点击:

How to identify invalid (corrupted) values stored in Oracle DATE columns

sqloracledateoracle10g

提问by spencer7593

Oracle 10.2.0.5

甲骨文 10.2.0.5

What is the easiest way to identify rows in a table that have "invalid" values in DATE columns. By "invalid" here what I mean is a binary representation that violates Oracle rules for date values.

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

I recently had an issue with an invalid date stored in a column.

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

I was able to use a query predicate to find a particular problematic row:

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

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

In the case I had, the century byte was invalid...

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

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

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

The century byte should be 100 + two digit century. In this case, there was an extra 100 added, as if the century value was "120", making the year "12011". (The only way I know to get invalid DATE values into the database is using OCI, using native 7-byte DATE representation.)

世纪字节应该是 100 + 两位数的世纪。在这种情况下,添加了额外的 100,就像世纪值是“120”一样,使年份成为“12011”。(我知道将无效 DATE 值输入数据库的唯一方法是使用 OCI,使用本机 7 字节 DATE 表示。)

In this case, the TO_CHAR function returned an identifiable string, which I could use for identifying the wonky DATE value.

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

My question: is there an more general or easier approach (preferably using a SQL SELECT statement) to identify rows with "invalid" values in DATE columns.

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

采纳答案by spencer7593

This identifies invalid months

这标识了无效的月份

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; 

Update using the same where clause, I found the month number was zero in these cases.

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

回答by APC

This is a pretty unusual scenario (although I have come across something similar once before). The more common problem is finding invalid dates which are held as strings in a date column. You could adapt the solution for that to your situation, by building your own date validator.

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

Something like this:

像这样的东西:

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;
/ 

This converts a date into a string and back again. It catches exceptions thrown by date casting. If the end product is not the same as the input date then presumably something got lost in translation; to be honest I'm not sure whether the 12011 date would cast successfully to a string, so this is a belt'n'braces approach. It's a bit tricky writing this utility without some test data!

这会将日期转换为字符串并再次返回。它捕获日期转换引发的异常。如果最终产品与输入日期不同,则可能在翻译中丢失了某些内容;老实说,我不确定 12011 日期是否会成功地转换为字符串,因此这是一种带大括号的方法。在没有一些测试数据的情况下编写这个实用程序有点棘手!

This query would identify all the non-valid dates:

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

 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';

回答by spencer7593

Without adding a function, a simple predicate

无需添加函数,一个简单的谓词

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

appears to be satisfactory to identify corrupted values stored in an Oracle DATE column. The addition of a function appears to be unnecessary. Checking for corrupted dates should be able to be done in a SQL SELECT statement, and not require a user to have CREATE FUNCTION privilege on the database.

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

回答by Fering

I had an 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".

我有一个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".

So to identify the rows that had a bad date I did the following.

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

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;

So all I did was create a cursor, loop through the elements and tested each one and display the identifier so I could easily find the bad rows.

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

回答by David Aldridge

I'd go for a method that can be implemented as a check constraint, probably through checking that the date is in the range of legal values.

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

However, ask yourself also whether it is valid to have a date of 1066-10-14? It is a legal value, but you probably do not have invoices printed on that day, for example. So you might like to roll the invalid date check into a larger issue of what you really consider to be valid in the context of your application.

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