更新期间Oracle日期损坏

chr*_*ris 6 oracle data-migration corrupt-data

我正在将一些数据从一个oracle架构/表迁移到同一数据库上的新架构/表.

迁移脚本执行以下操作:

create table newtable as select
  ...
  cast(ACTIVITYDATE as date) as ACTIVITY_DATE,
  ...
FROM oldtable where ACTIVITYDATE > sysdate - 1000;
Run Code Online (Sandbox Code Playgroud)

如果我查看原始数据,它看起来很好 - 这是一条记录:

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
Run Code Online (Sandbox Code Playgroud)

结果:

18-NOV-10                 NOV 18,2010                        18-NOV-2010 12:59:15                          Typ=12 Len=7: 120,110,11,18,13,60,16  
Run Code Online (Sandbox Code Playgroud)

迁移的数据,显示数据已损坏:

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
Run Code Online (Sandbox Code Playgroud)

结果:

18-NOV-10                 000 00,0000                         00-000-0000 00:00:00                           Typ=12 Len=7: 120,110,11,18,13,0,16   
Run Code Online (Sandbox Code Playgroud)

在35万条记录中,约有5000条显示出此问题.

谁能解释这是怎么发生的?

spe*_*593 4

更新:

我在 Oracle 支持网站上没有找到任何关于这种特定类型的 DATE 损坏的已发布参考。(可能就在那里,我的快速搜索只是没有找到它。)

  • 检查数据库是否有损坏日期的 Baddate 脚本 [ID 95402.1]
  • Bug 2790435 - 具有并行 SELECT 和类型转换的串行 INSERT 可能会插入损坏的数据 [ID 2790435.8]

DUMP() 函数的输出显示日期值确实无效:

Typ=12 Len=7: 120,110,11,18,13,0,16 
Run Code Online (Sandbox Code Playgroud)

我们期望分钟字节应该是 1 到 60 之间的值,而不是零。

DATE 值的 7 个字节依次表示世纪(+100)、年(+100)、月、日、小时(+1)、分钟(+1)、秒(+1)。

我唯一一次看到像这样的无效 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'
Run Code Online (Sandbox Code Playgroud)