2014-10-27 2 views
1

У меня есть приложение Python, которое использует pandas для поиска некоторых Excel-таблиц и вставки значений в базу данных оракула.Как вставить пустые даты excel в oracle с Python + Pandas?

Для ячеек даты, которые имеют значение, это работает нормально. Для пустых ячеек даты я вставляю NaT, который, как я думал, будет в порядке, но в Oracle, который становится некоторым странным недействительным временем, которое отображается как «0001-255-255 00:00:00» (что-то вроде MAXINT или 0 преобразуется в метку времени я угадывание?)

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

Выше бит данных в DataFrame, вы можете увидеть это нац.

Но это то, что я вижу в Oracle ..

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 в None, но я получаю сортированные ошибки ни с одной из них, которые кажутся подразумевают, что замена недействительна таким образом.

Любой способ обеспечить согласованность нулевой даты через эти хранилища данных ?!

+0

Как вы вставляете свое значение даты в БД? Каков тип столбца даты? –

+0

Добро пожаловать в переполнение стека. Пожалуйста, см. Мой ответ, и если у вас есть нерешенные вопросы, прокомментируйте это на мой ответ :-) –

+0

@SylvainLeroux В [231]: x ['TDATE']. Dtype Out [229]: dtype (' centech

ответ

0

Эта проблема исправлена ​​в Pandas 15.0.

Если возможно, обновите до Pandas> = 15.0. Начиная с этой версии, NaN и NaT должным образом сохраняются как NULL в базе данных.


После проведения некоторых экспериментов, оказалось, что панды проходят NaT в SQLAlchemy и вплоть до cx_Oracle - который, в свою очередь, слепо послать неверную дату для 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) 

Остерегайтесь того, что если вам когда-либо понадобится переписать другой DataFrame в ту же таблицу, вам сначала нужно будет удалить его содержимое, но не отказаться от него, иначе вы потеряете триггер одновременно. Например:

# 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

0

Надеюсь, что тип данных столбца даты в базе данных Oracle - DATE.

В этом случае, помните, дата имеет часть даты и времени даты вместе как ДАТА. При загрузке в базу данных убедитесь, что вы используете TO_DATE и поместите соответствующий формат даты и времени в литературу даты.

Это примерно загрузка. Теперь, чтобы отобразить, используйте TO_CHAR с надлежащим форматом даты и времени, чтобы увидеть значение, которым человеческие глаза хотят видеть значение datetime.

И, что касается значений 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) –

+0

Исправить. Я не обратил на это внимания. Спасибо, что указали это. –

Смежные вопросы