Sql 如何识别存储在Oracle日期列中的无效(损坏)值
Oracle 10.2.0.5 识别表中日期列中具有“无效”值的行的最简单方法是什么。这里我所说的“无效”是指违反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
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卡住了