SQLAlchemy+pg8000批量插入字典列表报错,求问题原因及解决方案
问题描述
尝试用SQLAlchemy结合pg8000驱动,将Pandas DataFrame转成字典列表后,通过原生SQL批量插入PostgreSQL数据库,代码如下:
import os import sqlalchemy import pandas as pd def connect_unix_socket() -> sqlalchemy.engine: db_user = os.environ["DB_USER"] db_pass = os.environ["DB_PASS"] db_name = os.environ["DB_NAME"] unix_socket_path = os.environ["INSTANCE_UNIX_SOCKET"] return sqlalchemy.create_engine( sqlalchemy.engine.url.URL.create( drivername="postgresql+pg8000", username=db_user, password=db_pass, database=db_name, query={"unix_sock": f"{unix_socket_path}/.s.PGSQL.5432"}, ) ) def _insert_ecoproduct(df: pd.DataFrame) -> None: db = connect_unix_socket() db_matching = { 'gtin': 'ecoproduct_id', 'ITEM_NAME_AS_IN_MARKETPLACE' : 'ecoproductname', 'ITEM_WEIGHT_WITH_PACKAGE_KG' : 'ecoproductweight', 'ITEM_HEIGHT_CM' : 'ecoproductlength', 'ITEM_WIDTH_CM' : 'ecoproductwidth', 'test_gtin' : 'gtin_test', 'batteryembedded' : 'batteryembedded' } df = df[db_matching.keys()] df.rename(columns=db_matching, inplace=True) data = df.to_dict(orient='records') sql_query = """INSERT INTO ecoproducts( ecoproduct_id, ecoproductname, ecoproductweight, ecoproductlength, ecoproductwidth, gtin_test, batteryembedded) VALUES (%(ecoproduct_id)s, %(ecoproductname)s,%(ecoproductweight)s,%(ecoproductlength)s, %(ecoproductwidth)s,%(gtin_test)s,%(batteryembedded)s) ON CONFLICT(ecoproduct_id) DO NOTHING;""" with db.connect() as conn: result = conn.exec_driver_sql(sql_query, data) print(f"{result.rowcount} new rows were inserted.")
但持续报错(见截图),疑问如下:
- pg8000是否支持这种命名参数映射?
- 是否需要更换为psycopg2驱动?
- 问题根源是什么?
EDIT 1:变量data的详情:
print(data) print(type(data)) [{'ecoproduct_id': '6941487202157', 'ecoproductname': 'HUAWEI FreeBuds Pro Bluetooth sans Fil ', 'ecoproductweight': '4', 'ecoproductlength': '0.220', 'ecoproductwidth': '0.99', 'gtin_test': False, 'batteryembedded': 0}] <class 'list'>
解答
1. pg8000对命名参数的支持情况
pg8000支持命名参数,但语法和psycopg2不同——它要求用:param_name的格式,而非psycopg2的%(param_name)s格式。你当前SQL使用的是psycopg2风格的参数语法,这是报错的核心原因。
2. 是否需要更换为psycopg2驱动?
不需要强制更换,只要调整参数格式就能继续使用pg8000。但如果你的业务场景依赖psycopg2的特定特性(如COPY批量导入、PostgreSQL扩展支持),也可以考虑切换,两者都是成熟的PostgreSQL驱动。
3. 问题根源及修复方案
根源
SQL语句中使用了pg8000不识别的%(xxx)s参数占位符,导致驱动无法解析字典列表中的参数映射。
修复步骤
修改SQL语句的参数格式为pg8000支持的:xxx即可:
sql_query = """INSERT INTO ecoproducts( ecoproduct_id, ecoproductname, ecoproductweight, ecoproductlength, ecoproductwidth, gtin_test, batteryembedded) VALUES (:ecoproduct_id, :ecoproductname, :ecoproductweight, :ecoproductlength, :ecoproductwidth, :gtin_test, :batteryembedded) ON CONFLICT(ecoproduct_id) DO NOTHING;"""
调整后,pg8000就能正确匹配字典列表中的参数键,完成批量插入操作。
另外,也可以考虑使用SQLAlchemy的ORM层或execute方法配合参数绑定,但直接修改占位符格式是最直接的修复方式。
内容的提问来源于stack exchange,提问作者IndiaSke
相关产品推荐
相关产品推荐

