从2050年到1950年的神秘变化

Jaa*_*nna 1 oracle plsql oracle11g plsqldeveloper

有一些不寻常的事情发生.虽然移民,我有2050年之后一些时间(例如,二○五○年五月二十○日,21.11,2051),但由于某些原因,他们的Oracle更改为1950年,1951年等.如果你问我,它是由客户报告很烦人.这些是退休日期,所以很明显他们不能在20世纪50年代和60年代

原始表中的日期类似于YYYYMMDD格式,即20500130.所以这是我的合并声明

MERGE INTO employment_data emp                                                     
   USING   temp_02 src
   ON      (TO_NUMBER(src.id) = emp.id)
   WHEN MATCHED THEN UPDATE SET 
       emp.retirement_day = DECODE(TO_NUMBER(src.retirement), 0, NULL, TO_DATE(src.retirement, 'YYYY.MM.DD'));
Run Code Online (Sandbox Code Playgroud)

其他日期还可以(例如20301204),但是2050年之后的任何日期都是疯狂的.知道我怎么能解决这个烦恼?

Thx提前:-)

Vin*_*rat 8

问题在于DECODE力量是一种隐含的转换.DECODE函数的返回数据类型由规则确定:

DECODE(expr, search, result [, search, result]* [, default])
Run Code Online (Sandbox Code Playgroud)

在比较之前,Oracle会自动将expr每个search值转换为第一个值的数据类型search.Oracle会自动将返回值转换为与第一个相同的数据类型result.如果第一个result具有数据类型CHAR或第一个result为null,则Oracle将返回值转换为数据类型VARCHAR2.

在Oracle中NULL具有默认数据类型,VARCHAR2因此您的DECODE表达式等效于:

DECODE(TO_NUMBER(src.retirement), 0, 
       NULL, 
       TO_CHAR(TO_DATE(src.retirement, 'YYYY.MM.DD')));
Run Code Online (Sandbox Code Playgroud)

如果没有格式,则TO_CHAR使用您的NLS_DATE_FORMAT会话设置,可能是DD-MON-RR失去世纪信息的默认值.

正如在这里可以注意到相关的问题,对规则RR如下:

  • 如果指定的两位数年份是00到49,那么
    • 如果当前年份的最后两位数字是00到49,那么返回的年份与当前年份的前两位数字相同.
    • 如果当前年份的最后两位数字是50到99,那么返回年份的前2位数字比当前年份的前2位数字大1.
  • 如果指定的两位数年份是50到99,那么
    • 如果当前年份的最后两位数字是00到49,那么返回年份的前2位数字比当前年份的前2位数字少1.
    • 如果当前年份的最后两位数字是50到99,那么返回的年份与当前年份的前两位数字相同.

这就是2050年之前的日期没有引发神秘行为的原因!