我正在将一些oracle架构/表中的数据迁移到同一数据库中的新架构/表。
迁移脚本执行以下操作:
create table newtable as select
...
cast(ACTIVITYDATE as date) as ACTIVITY_DATE,
...
FROM oldtable where ACTIVITYDATE > sysdate - 1000;
如果我查看原始数据,它看起来很好 - 这是一条记录:
select
activitydate,
to_char(activitydate, 'MON DD,YYYY'),
to_char(activitydate, 'DD-MON-YYYY HH24:MI:SS'),
dump(activitydate),
length(activitydate)
from orginaltable where oldpk = 1067514
结果:
18-NOV-10 NOV 18,2010 18-NOV-2010 12:59:15 Typ=12 Len=7: 120,110,11,18,13,60,16
迁移的数据,显示数据已损坏:
select
activity_date,
to_char(activity_date, 'MON DD,YYYY'),
to_char(activity_date, 'DD-MON-YYYY HH24:MI:SS'),
dump(activity_date),
length(activity_date)
from newtable
where id = 1067514
结果:
18-NOV-10 000 00,0000 00-000-0000 00:00:00 Typ=12 Len=7: 120,110,11,18,13,0,16
350k记录中约有5000个记录显示此问题。
任何人都可以解释这是怎么发生的吗?
答案 0 :(得分:4)
更新:
我在Oracle支持网站上找不到任何已发布的对此特定类型的DATE损坏的引用。 (它可能在那里,我的快速搜索只是没有打开它。)
DUMP()函数的输出显示日期值确实无效:
Typ=12 Len=7: 120,110,11,18,13,0,16
我们希望分钟字节应该是一到六十之间的值,而不是零。
DATE值的7个字节依次表示世纪(+100),年(+100),月,日,小时(+1),分钟(+1),秒(+1)。< / p>
我唯一一次看到无效的DATE值,当DATE值作为绑定变量提供时,来自Pro * C程序(其中绑定值以内部7字节表示形式提供,完全绕过正常值)捕获无效日期的验证例程,例如2月30日)
根据您发布的Oracle语法,没有理由期待您所看到的行为。
这可能是一个虚假的异常(内存损坏?),或者如果这是可重复的,那么它就是Oracle代码中的一个缺陷(bug)。如果这是Oracle代码中的一个缺陷,最可能的嫌疑人将是未修补版本中的“新”功能。
(我知道CAST是一个标准的SQL函数,在其他数据库中存在很长时间。我想我已经老了,并且从未将它引入我的Oracle语法库中。我不知道Oracle的版本是什么它引入了CAST,但我会在它出现的第一个版本中远离它。)
另一位评论者指出的大“红旗”是CAST( datecol AS DATE)
。
您希望优化器将其视为等同于date_col ...但过去的经验告诉我们TO_NUMBER( number_col )
实际上被优化程序解释为TO_NUMBER( TO_CHAR ( number_col ) )
。
我怀疑那些不需要的CAST会发生类似的情况。
根据您显示的那条记录,我怀疑问题是值为“59”值的分钟或秒,而可能是“23”的小时值,将显示错误。
我会尝试检查分钟,小时或秒存储为0的地方:
SELECT id, DUMP(activitydate)
FROM newtable
WHERE DUMP(activitydate) LIKE '%,0,%'
OR DUMP(activitydate) LIKE '%,0'
答案 1 :(得分:2)
我见过类似于spence7593的东西,再次使用Pro * C. 可以使用DBMS_STATS包以编程方式创建无效日期。 不确定是否有类似的机制来扭转这种情况。
create or replace function stats_raw_to_date (p_in raw) return date is
v_date date;
v_char varchar2(25);
begin
dbms_stats.CONVERT_RAW_VALUE(p_in, v_date);
return v_date;
exception
when others then return null;
end;
/
select stats_raw_to_date(utl_raw.cast_to_raw(
chr(120)||chr(110)||chr(11)||chr(18)||chr(13)||chr(0)||chr(16)))
from dual;