Массовая вставка в postgres таблицу из python - PullRequest
0 голосов
/ 17 июня 2020

Я хочу вставить / обновить значения из кадра данных pandas в таблицу postgres. У меня есть уникальный кортеж (a, b) в таблице postgres. Если кортеж уже существует, я хочу обновить только третье значение c, если кортеж не существует, я хочу создать тройку (a, b, c).

Что больше всего эффективный способ сделать это? Я предполагаю, что это какая-то объемная вставка, но я не совсем уверен, как именно.

1 Ответ

0 голосов
/ 17 июня 2020

Вы можете преобразовать ваш фрейм данных в CTE https://www.postgresql.org/docs/current/queries-with.html и затем вставить данные из CTE в таблицу. Примерно так:

def convert_df_to_cte(df):
    vals = ', \n'.join([f"{tuple([f'$str${e}$str$' for e in row])}" for row in df.values])
    vals = vals.replace("'$str$", "$str$")
    vals = vals.replace("$str$'", "$str$")
    vals = vals.replace('"$str$', "$str$")
    vals = vals.replace('$str$"', "$str$")
    vals = vals.replace('$str$nan$str$', 'NULL')

    columns = ', \n'.join(df.columns)

    sql = f"""
    WITH vals AS (
        SELECT 
            {columns}
        FROM 
            (VALUES {vals}) AS t ({columns})
    )
    """
    return sql


df = pd.DataFrame([[1, 2, 3]], columns=['col_1', 'col_2', 'col_3'])

cte_sql = convert_df_to_cte(df)
sql_to_insert = f"""
{cte_sql}

INSERT INTO schema.table (col_1, col_2, col_3)
SELECT 
    col_1::integer, -- don't forget to cast to right type to avoid errors
    col_2::integer, -- don't forget to cast to right type to avoid errors
    col_3::character varying
FROM 
    vals
ON CONFLICT (col_1, col_2) DO UPDATE SET
    col_3 = excluded.col_3;
"""

run_sql(sql)
...