Как использовать именованные привязки с массовыми вставками (executemany) в cx_Oracle из pandas dataframe

Я не уверен, как выполнить массовую вставку в Oracle из Python 3, используя именованные переменные связывания, когда исходные данные находятся в кадре данных Pandas. Код ниже показывает мою попытку. С безымянными привязками это довольно просто, но ошибочно, поскольку порядок привязок должен быть таким же, как столбцы в Dataframe.

    "Named pandas binds with cursor.executemany in cx_oracle, how ?"
    import pandas as pd
    import cx_Oracle
    # create table t( a number, b varchar2 (20 char));
    df = pd.DataFrame(data={'a': [1, 2], 'b': ["Dog", "Cat"]})
    conn = cx_Oracle.connect('/@DB')
    cur = conn.cursor()
    # Bulk insert, numbered binds work
    cur.execute("truncate table t")
    cur.executemany("insert into t (a, b) values (:1, :2)", df.values.tolist())
    print(pd.read_sql("select a, b from t", con=conn))
    # Insert, named binds work
    cur.execute("truncate table t")
    cur.execute("insert into t (a, b) values (:cc, :dd)", dd="Donkey", cc=1)
    print(pd.read_sql("select a, b from t", con=conn))
    # Bulk insert, named binds do not work
    cur.execute("truncate table t")
    cur.executemany("insert into t (a, b) values (:cc, :dd)", dd=df['b'].values.tolist(), cc=df['a'].values.tolist())
    # TypeError: Required argument 'parameters' (pos 2) not found
    print(pd.read_sql("select a, b from t", con=conn))
    #
    conn.commit()
    cur.close()
    conn.close()

Нильс

2 ответа

Решение

Если вы намереваетесь использовать именованные переменные связывания, вам нужно будет сделать следующее:

[{"a" : 1, "b" : "Dog"}, {"a" : 2, "b" : "Cat"}]

Другими словами, вам нужно создать список словарей вместо списка списков.

Энтони, конечно, прав. Следующий код (модифицированный из моего исходного вопроса) демонстрирует это. Обратите внимание, что переменные именованного связывания:b,:a расположены в обратном порядке по сравнению со столбцами в кадре данных и даже совпадают (что иллюстрирует основную причину, по которой я хочу именованные привязки, а именно защиту от использования порядка связываний и столбцы данных совпадают)

Спасибо.

"""
Named cx_Oracle bind variables with cursor.executemany and pandas dataframe as input
The trick is to convert the dataframe to a list of dictionaries
"""
import pandas as pd
import cx_Oracle
# create table t(a number, b varchar2 (20 char));
df = pd.DataFrame(data={'a': [1, 2], 'b': ["Dog", "Cat"]})
print(df.to_dict('records'))
conn = cx_Oracle.connect('/@DB')
cur = conn.cursor()
cur.executemany("insert into t (b, a) values (:b, :a)", df.to_dict('records'))
print(pd.read_sql("select a, b from t", con=conn))
conn.rollback()
cur.close()
conn.close()
# Output
#[{'a': 1, 'b': 'Dog'}, {'a': 2, 'b': 'Cat'}]
#   A    B
# 0  1  Dog
# 1  2  Cat
Другие вопросы по тегам