2014-10-27 114 views
1

我有一個Python應用程序使用熊貓來挖掘一些excel電子表格並將值插入到oracle數據庫中。如何用Python + Pandas將空的excel日期插入到oracle中?

對於具有值的日期單元格,此工作正常。對於空白的日期單元格,我插入了一個NaT,我認爲這樣會很好,但是在Oracle中變成了一些奇怪的無效時間,顯示爲「0001-255-255 00:00:00」(類似於MAXINT或0被轉換成一個時間戳我猜?)

In[72]: x.iloc[0][9] 
Out[72]: NaT 

以上是對數據幀的數據位,你可以看到它是在NAT。

但是,這是我在甲骨文看..

SQL> select TDATE from TABLE where id=5067 AND version=5; 

TDATE 
--------- 
01-NOVEMB 

SQL> select dump("TDATE") TABLE where id=5067 AND version=5; 

DUMP("TDATE") 
-------------------------------------------------------------------------------- 
Typ=12 Len=7: 100,101,255,255,1,1,1 

我試圖做df.replace和/或df.where NAT的轉換爲無,但我得到任何的這些,似乎是配合錯誤暗示替代無效的方式。

確保跨這些數據存儲的空日期保持一致的任何方法?

+0

如何在數據庫中插入日期值?日期欄的類型是什麼? – 2014-10-27 16:05:59

+0

歡迎來到Stack Overflow。請參閱我的答案,如果您有任何懸而未決的問題,請評論它放在我的回答:-) – 2014-10-27 16:06:01

+0

@SylvainLeroux在[231]:X [「TDATE」] D類輸出[229]:D型(「 centech 2014-10-27 17:18:48

回答

0

此問題已在Pandas 15.0中修復。

如果可以,更新到Pandas> = 15.0。從該版本開始,NaNNaT在數據庫中正確存儲爲NULL。


已經進行了一些實驗後,似乎熊貓傳遞NaT到SQLAlchemy的和向下cx_Oracle - 這反過來一味發送無效日期甲骨文(這反過來不抱怨)。

無論如何,我能找到的是添加一個BEFORE INSERT TRIGGER來修復傳入的時間戳。爲此,您必須首先手動創建表格。

-- Create the table 
CREATE TABLE W ("ID" NUMBER(5), "TDATE" TIMESTAMP); 

然後扳機:

-- Create a trigger on the table 
CREATE OR REPLACE TRIGGER fix_null_ts 
BEFORE INSERT ON W 
FOR EACH ROW WHEN (extract(month from new.tdate) = 255) 
BEGIN 
    :new.tdate := NULL; 
END; 
/

之後,從Python中,使用pandas.DataFrame.toSql(..., if_exists='append')

>>> d = [{"id":1,"tdate":datetime.now()},{"id":2}] 
>>> f = pd.DataFrame(d) 
>>> f.to_sql("W",engine, if_exists='append', index=False) 
#      ^^^^^^^^^^^^^^^^^^ 
#   don't drop the table! append data to an existing table 

並檢查:

>>> result = engine.execute("select * from w") 
>>> for row in result: 
...  print(row) 
... 
(1, datetime.datetime(2014, 10, 31, 1, 10, 2)) 
(2, None) 

要注意的是,如果你需要的其他數據幀重寫到同一個表,你首先需要刪除的內容 - 而不是放棄它,否則你會在同一時間失去了扳機。例如:

# Some new data 
>>> d = [{"id":3}] 
>>> f = pd.DataFrame(d) 

# Truncate the table and write the new data 
>>> engine.execute("truncate table w") 
>>> f.to_sql("W",engine, if_exists='append', index=False) 
>>> result = engine.execute("select * from w") 

# Check the result 
>>> for row in result: 
...  print(row) 
... 
(3, None) 
+1

謝謝!雖然我現在還不能升級大熊貓(現在已經接近發佈版本來提升主要組件),但是使用一大堆你給的指針我能夠在短期內解決這個問題。長期養熊貓已經在計劃中,所以這會更好。謝謝! – centech 2014-10-31 20:19:07

0

我希望Oracle數據庫中日期列的數據類型是DATE

在這種情況下,請記住,日期的日期部分和時間部分一起作爲日期。在加載到數據庫時,請確保使用TO_DATE並將正確的日期時間格式設置爲日期文字。

這是關於加載。現在,要顯示,使用TO_CHAR以適當的日期時間格式查看人眼想要查看日期時間值的方式的值。

而且,關於NULL值,除非您有NOT NULL約束,否則我看不到任何加載問題。無論如何,NULL值將加載爲NULL。如果要操作NULL值,請使用NVL函數,並使用所需值替換NULL值。

+0

_「我希望Oracle數據庫中日期列的數據類型是DATE。」_根據'DUMP'輸出,它是[數據類型12是'DATE'](http://docs.oracle.com/ cd/B28359_01/server.111/b28286/sql_elements001.htm#sthref37) – 2014-10-27 16:11:27

+0

正確。我忽略了它。感謝您指出。 – 2014-10-27 16:14:26