2014-10-27 108 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