Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何识别存储在Oracle日期列中的无效(损坏)值_Sql_Oracle_Date_Oracle10g - Fatal编程技术网

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

Sql 如何识别存储在Oracle日期列中的无效(损坏)值,sql,oracle,date,oracle10g,Sql,Oracle,Date,Oracle10g,Oracle 10.2.0.5 识别表中日期列中具有“无效”值的行的最简单方法是什么。这里我所说的“无效”是指违反Oracle日期值规则的二进制表示 我最近遇到了一个问题,列中存储的日期无效 我能够使用查询谓词查找特定的有问题的行: WHERE TO_CHAR(date_expr,'YYYYMMDDHH24MISS') = '00000000000000' 在我的例子中,世纪字节是无效的 select dump(h.bid_close_date) from mytable h where

Oracle 10.2.0.5

识别表中日期列中具有“无效”值的行的最简单方法是什么。这里我所说的“无效”是指违反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”。(我所知道的将无效日期值输入数据库的唯一方法是使用OCI,使用本机7字节的日期表示。)

在本例中,TO_CHAR函数返回一个可识别的字符串,我可以用它来识别不可靠的日期值


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

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

大概是这样的:

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年的日期是否会成功地将一个字符串,所以这是一个带'n'支架的方法。在没有测试数据的情况下编写这个实用程序有点棘手

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

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

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


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

< P>不添加函数,一个简单谓词< /P>
TO_CHAR(date_col,'YYYYMMDDHH24MISS') = '000000000000'

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

这会标识无效的月份

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子句进行更新时,我发现在这些情况下月份数为零。

我有一个
SQL错误:ORA-01841:(完整)年份必须介于-4713和+9999之间,而不是0
184100000-“(完整)年份必须介于-4713和+9999之间,而不是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;

因此,我所做的只是创建一个光标,循环遍历元素并测试每个元素,然后显示标识符,这样我就可以轻松找到错误行。

您能选择所有不在指定有效范围内的日期吗?Oracle(9.x?)的早期版本中有一个错误这使得间隔值除以零无法被检测到,并产生无效值。您是如何首先将它们放入数据库的?@a_horse_with_no_name:不完全清楚这些损坏的日期值是如何插入的。。。开发人员不知道这可能发生在软件的什么地方。我相信OCI(Oracle调用接口)允许传递Oracle二进制表示(7字节,cc+100,yy+100,mm,dd,hh+1,mi+1,ss+1),并且使用此功能“绕过”Oracle通常对日期值执行的检查。(这让软件有责任确保提供给Oracle的值是有效的。)+1假设这确实有效(我也没有测试数据),我更喜欢这样做,而不是解析
dump
返回的字符串。按照许多函数的一般工作方式,可能希望返回null,如果
p_date
为空。对于这种特殊用途,接受null并将其报告为一个好的日期是有意义的。@ShannonSeverance-在这种情况下,我认为最明智的选择是过滤查询,因此我们只关心填充日期列的行。后面的问题与这个问题有点相关:Oracle在数据损坏方面的行为(无效)日期列的内容…但回到这里提出的问题…我们可以编写什么SQL查询来“验证”日期列的内容,并仅返回日期列值已损坏的行(即,根据Oracle日期存储内容规范无效)这并没有回答我提出的问题,这是关于识别Oracle数据库日期列中现有损坏的最佳方法。事实上不是——这是关于如何选择方法以及更广泛地考虑数据有效性的建议。是否可以使用类似的模式来识别无效的“世纪”和“年”值,在Oracle内部7字节表示中100+cc,100+yy,mm,dd,…(我考虑使用
DUMP
,但解析字符串并验证组件(在SQL查询上下文中)看起来有点吓人。我想要的是一个简单的谓词,可以测试/验证日期列中的值,类似于
其中DATE\u col是any\u invalid\u value
…这就是我找不到的。你不能做这个简单的查询,因为any\u invalid\u value会破坏从行中的字节到pr中日期类型的转换Gram。Oracle数据的内部和外部表示在这里遇到了障碍。SQL在内部调用类似于OCIDateCheck()的东西。我在这里写过关于它的博客[。你被que卡住了