Контекст
Я пытаюсь обновить / вставить базу данных PostgreSQL с содержимым pandas DataFrame используя psycopg2 .
Я повторяю строки DataFrame, потому что мы не можем использовать метод .to_sql()
при использовании оператора UPSERT .
Short
То, что я пытаюсь сделать, это развернуть имена столбцов и их значения в строку запроса SQL с выражениями, отмеченными звездочкой, для имен столбцов и фактические значения.
Все работает нормально, за исключением двух мелких неловких деталей;
- имена и значения столбцов разделяются не запятой, а пробелом,
- имена столбцов заключаются в одинарные кавычки, отсюда и ошибка.
Код, сведения и сообщение об ошибке:
Вот фрагмент кода, который я использую;
# Python 3.6.9 (default, Apr 18 2020, 01:56:04)
import pandas as pd # -- version 1.0.3
import psycopg2 # -- version 2.8.5 (dt dec pq3 ext lo64)
df = pd.DataFrame({'__col1__name_': [1],
'__col3__name_': [2],
'__col3__name_': ['three'],
'__col4__name_': [4],
'_col5_name_': [5],
'_col6_name_': [6],
'_col7_name_': [7.0],
'_col8_name_': [8.0],
})
cols = list(df.columns)
nCols = len(cols)
name = "tablename"
for i, row in df.iterrows():
# Warning: ugly query here, but I want it as compact as possible
# and I need to pass the table name as an argument because I'm actually running this
# in a for loop over some tables which may change in the future, so I don't want
# to patch the code much each time a column is renamed or added to the database.
query = """
INSERT INTO """+"schema.{}".format(name)+"""
("""+nCols*'%s '+""")
VALUES ("""+nCols* '%s ' +""")
ON CONFLICT (%s) DO UPDATE SET
("""+(nCols)*'%s '+""") = ("""+(nCols)*'%s '+""")
WHERE %s = %s
"""
with psycopg2.connect(**DB_PARAMS) as conn:
with conn.cursor() as curs:
print(curs.mogrify(sql_query, ((*cols, *row, cols[0], *cols, *row, cols[0], row[0]))))
curs.execute(sql_query, ((*cols, *row, cols[0], *cols, *row, cols[0], row[0])))
И я получаю это SyntaxError
:
SyntaxError: syntax error at or near "'__col1__name_'"
LINE 3: ('__col1__name_' '__col3__name_' '__col4__name_' '_c..
^
У меня такая же ошибка, если я копирую и вставляю вывод mogrify
непосредственно в pgAdmin , например.
Вывод Mogrify выглядит следующим образом:
INSERT INTO schema.tablename
('__col1__name_' '__col3__name_' '__col4__name_' '_col5_name_' '_col6_name_' '_col7_name_' '_col8_name_' )
VALUES (1 'three' 4 5 6 7.0 8.0 )
ON CONFLICT ('__col1__name_') DO UPDATE SET
('__col1__name_' '__col3__name_' '__col4__name_' '_col5_name_' '_col6_name_' '_col7_name_' '_col8_name_' ) = (1 'three' 4 5 6 7.0 8.0 )
WHERE '__col1__name_' = 1
Это не работает в Postgres из-за одинарной кавычки.
Я действительно стараюсь не составлять строку запроса SQL с .format()
(за исключением table name) перед отправкой на curs.execute()
, но пусть psycopg2
обрабатывает аргументы за меня, что, как мне сказали, является хорошей идеей.
Question
Как я могу заключить имена столбцов в двойные кавычки и разделить их запятой?
То же самое для значений; они не разделяются запятой.