2013-05-31 57 views
1

有一些不尋常的事情發生。在遷移期間,我有一些日期超過2050年(例如,20.05.2050,21.11,2051),但由於某些原因,甲骨文將它們更改爲1950年,1951年等。如果您詢問我並且它是由客戶報告的,則非常煩人。這些都是退休的日期,以便他們顯然無法在20世紀50年代和60年代從2050年到1950年的神祕變化

在原表的日期是像YYYYMMDD格式又名20500130.因此,這裏是我的MERGE語句

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

其他日期都OK(例如, 20301204),但2050年以後的任何日期都會發生。任何想法我怎麼可能解決這個煩惱?

Thx提前:-)

+2

可能的解釋在這裏http://stackoverflow.com/questions/16847010/different-dates-oracle-11g-with-toad – Noel

+1

什麼是格式?你提到YYYYMMDD(20500130),然後使用YYYY.MM.DD,並且還提到了(04122030)的例子,我猜想它是MMDDYYYY。 – tbone

+0

是的,有些東西沒有加起來。如果你在像'2050.05.20'這樣的值上調用'TO_NUMBER()',你會得到一個無效的數字異常,所以'DECODE'的第一個條件應該拋出非零的日期。 –

回答

8

的問題是,所述DECODE強制的隱式轉換。和

DECODE(expr, search, result [, search, result]* [, default]) 

甲骨文自動轉換expr每個search值比較之前第一search值的數據類型:所述DECODE函數的返回數據類型是由rule確定。 Oracle會自動將返回值轉換爲與第一個result相同的數據類型。如果第一個result的數據類型爲CHAR或(如果第一個result爲空),則Oracle將返回值轉換爲數據類型VARCHAR2

在Oracle NULLVARCHAR2默認的數據類型使您DECODE表達式等價於:

DECODE(TO_NUMBER(src.retirement), 0, 
     NULL, 
     TO_CHAR(TO_DATE(src.retirement, 'YYYY.MM.DD'))); 

沒有格式的TO_CHAR使用您NLS_DATE_FORMAT會話設置,可能是默認DD-MON-RR它失去世紀信息。

在本related question指出,對於RR規則是as follow

  • 如果指定的兩位數的年份是00到49,然後
    • 如果的最後兩位數字當前年份爲00到49,那麼返回的年份與當年的前兩位數字相同。
    • 如果當年的最後兩位數字是50到99,則返回年份的前兩位數字比當前年份的前兩位數字大1。
  • 如果指定的兩位數的年份是50〜99,然後
    • 如果當前年的最後兩位數字是00至49,則返回的一年中的前2位是1以下比當年的前兩位數字要多。
    • 如果當年的最後兩位數字是50到99,那麼返回的年份與當年的前兩位數字相同。

這就是爲什麼在2050年之前的日期還沒有觸發神祕的行爲!

1

我已經想通了,並認爲它可以幫助別人。

我不確定這是Oracle設置的問題還是PL/SQL Developer的一些難題。無論如何,我先檢查了NLS_DATE_FORMAT。

SELECT value FROM v$nls_parameters 
WHERE parameter = 'NLS_DATE_FORMAT' 

它表明它被設置爲DD-MON-RR。

現在不更改配置,我想只更改遷移會話和該會話的設置。

Alter SESSION SET nls_date_format = 'dd-mon-yyyy'; 

然後運行合併語句。

MERGE INTO employment_data emp              
    USING temp_02 src 
    ON  (TO_NUMBER(src.id) = emp.id) 
    WHEN MATCHED THEN UPDATE SET 
     emp.retirement_day = TO_CHAR(TO_DATE(src.retirement,'YYYY.MM.DD')); 

這個工作。

+2

適合你的幾條規則:1.不要將日期存儲或操作爲DATE數據類型以外的任何其他日期。 2.永遠不要依賴隱式日期轉換 - 您應始終在任何轉換中指定日期格式。 –