2013-05-07 98 views
1

我正在研究將數據從IBM iSeries服務器導入到MSSQL 2008 R2數據庫的程序。不幸的是,一些開發人員很久以前決定將日期存儲爲十進制類型,這有效地打破了用於存儲日期的CYYMMDD格式。將IBM iSeries DB2小數日期類型轉換爲DateTime對象

例如,以這種格式,1995年8月1日將被存儲爲:0950801.然而,實際存儲在數據庫中的是95081,如果我嘗試將其轉換爲System.DateTime,那麼顯然會引發異常。

如果這是一個簡單的缺少前導0的問題,我可以很容易地將它添加到字符串,然後再嘗試轉換它。然而,有幾個(數千個,真的)日期只有3或4位數字,我真的不知道該怎麼做。例如,存儲的日期爲1128.我不知道該怎麼做。如果我只用3個前導0來轉換它,它會產生一個明顯不正確的日期。

那麼,有沒有人知道解析這些日期的可靠方法?直接通過SQL select語句,或者在C#中進行一些操作?或者我只是假設3位和4位數字的日期從來沒有正確輸入過,並且放棄了這樣的日期?

+0

你知道日期應該代表什麼嗎?他們是DOB等...? – 2013-05-07 21:19:58

+0

@Robbie他們代表不同的東西,包括DOB的,但也是客戶賬戶歷史表中的交易日期。對於交易日期,我可以對年度進行一番探討,因爲顯然在我們公司做或者將來之前交易不可能存在。但是這對生日不起作用... – Jedediah 2013-05-07 21:23:16

+0

我不認爲3或4位數字的日期本身就是一個問題。我傾向於將它們原樣導入並稍後處理。你見過這個嗎? http://www.techrepublic.com/forum/questions/101-278438/cyymmdd-format-in-db2 – 2013-05-07 21:30:16

回答

0

十進制CYYMMDD是一種標準的IBM格式,其中C在1900年爲零,在2000年爲1。這可以追溯到S/38(1982年左右)或更早。但我不記得他們在S/38之前使用它,它是AS/400和iSeries的前身。

我建議在DB2中創建一個用戶定義的函數,將您的小數日期轉換爲ISO日期值。 DB2 for i將緩存DETERMINISTIC函數的結果,因此每次查看之前處理的日期值時都不必重新計算函數。

更新

下面是一個例子我適於將壓縮十進制(8,0)在ccyymmd或YYMMDD格式值到DB2日期:

CREATE OR REPLACE FUNCTION 
    Cvt_Dec8cymd_to_Date (dtin dec(8,0)) 
         returns date 
    LANGUAGE SQL 
    CONTAINS SQL 
    DETERMINISTIC       -- caches results 
    NO EXTERNAL ACTION 
    RETURNS NULL ON NULL INPUT 
    NOT FENCED 
    SET OPTION DBGVIEW = *SOURCE 

prc: BEGIN NOT ATOMIC      -- don't rollback on error 
      DECLARE ans date;           
      DECLARE cymd dec(8,0);          
      -- add declarations for conditions and handlers here 

      SET ans = null;             
      CASE               
      WHEN dtin > 999999 THEN   -- more than 6 digits given 
       set cymd = dtin;            
      WHEN dtin < 400000 THEN   -- yr < 40 means 2000's  
       SET cymd = 20000000 + dtin;         
      ELSE       -- yr >= 40 means 1900's  
       SET cymd = 19000000 + dtin;         
      END CASE;              

      --convert to date            
      SET ans = date(insert(insert(digits(cymd),7,0,'-'),5,0,'-')); 
      RETURN ans;              
     END prc               
; 

它是簡單的邏輯,沒有錯誤處理無效值。

其他人可能會有一個更好的例子,或者可能會改善這個。

+0

我可以嘗試明天發佈代碼。 – WarrenT 2013-05-07 23:42:44

+0

這很棒,如果你有時間 – Jedediah 2013-05-08 13:40:03

0

我會建議看看程序(和,特別是任何改變評論 [假設他們存在])插入/更新表(查詢DB2爲此)。如果日期格式發生更改(例如Y2K)以及原因,更改評論將有望告訴您。

同樣看着閱讀DB的任何程序,可能有特殊代碼來處理日期。可能有代碼來確定日期格式。

95081也可能是序號日期(YYDDD)其中DDD是年的日子。請參閱Ordinal or Julian-Date。這些日期在一個階段流行。

我猜想DB字段原本是YYMMDD沒有世紀。對於Y2k,格式可能更改爲CYYMMDD。像1128(和221)這樣的日期可能是YYMMDD日期,在Y2k更改之前創建的位置(或者在原始y2k實現中遺漏並在稍後更改的位置)。

+0

不幸的是,據我所知,沒有讀/寫程序。每個人都通過終端仿真器直接與數據庫交互,這是我懷疑數據不正確而不是格式問題的原因之一。 – Jedediah 2013-05-08 13:39:25

+0

該示例是950801,而不是95081.它似乎是1995年8月1日。 – WarrenT 2013-05-10 23:15:21

+0

@ Hg3這些程序很可能是在終端仿真程序中以交互方式運行。如果您擁有(或獲得)5250仿真器,則可以登錄並查找程序源。最常用的方法是使用STRPDM命令(啓動程序開發管理器)。在PDM中,可以使用庫,然後使用庫中的對象(查找源文件),然後使用源文件的「成員」。源文件最有可能被命名爲QxxxSRC,其中xxx可以是CL,RPG,RPGLE,CBL,CBLLE或其他程序語言標識符。但坦率地說,這可能是一個巨大的時間吸收,收益不大。 – WarrenT 2013-05-10 23:43:30

0

經過大量的試驗和錯誤,我想我已經找到了解決方案。

 
SELECT 
(CASE WHEN INT(SUBSTR(DIGITS(DTPSTD), 1,2)) > MOD(YEAR(CURRENT DATE),100) 
      THEN DATE(CONCAT(CONCAT(CONCAT(SUBSTR(DIGITS(DTPSTD), 3,2), '/'), CONCAT(SUBSTR(DIGITS(DTPSTD), 5,2), '/')), CONCAT('19', SUBSTR(DIGITS(DTPSTD), 1,2)))) 
     ELSE DATE(CONCAT(CONCAT(CONCAT(SUBSTR(DIGITS(DTPSTD), 3,2), '/'), CONCAT(SUBSTR(DIGITS(DTPSTD), 5,2), '/')), CONCAT('20', SUBSTR(DIGITS(DTPSTD), 1,2)))) 
     END) AS TransactionDate 
FROM TABLE_NAME 
WHERE CUSTOMER_ID = 1 

DTPSTD是「發佈日期」

據我所知,這適用於在1900年或2000的任何日期,但不會對日期比1月 - 1900年長工作。在我的情況下,這很好,因爲我沒有任何日期比1920年或更早存儲的日期。

+1

查看我的嵌套INSERT()代碼,它比一堆CONCAT()和SUBSTR()函數簡單得多。另外你可能會發現'A || B || C'比'CONCAT(A,B,C)'更簡單 – WarrenT 2013-05-10 23:20:52