如何向PostgreSQL表插入列名匹配的CSV数据并解决relation不存在报错
问题解决方法
psycopg2.errors.UndefinedTable: relation "table_name" does not exist 报错的核心原因是:你将Python变量名
table_name、x直接硬编码写在了SQL语句字符串中,PostgreSQL会将这两个字符串当做实际的表名、列名去检索,不会自动替换为你Python代码中定义的同名变量的值,自然找不到名为table_name的表。
你代码中存在的其他问题
- 插入逻辑错误:当前逻辑是外层遍历列、内层遍历CSV行,每次只插入单个列的值,既不符合插入整行数据的逻辑,也会因为csv.reader是一次性迭代器,第一次遍历完列之后后续遍历都会读取空值。
- 标识符传值错误:psycopg2的参数化查询
%s仅支持传数据值,不支持传表名、列名这类SQL标识符,动态标识符需要用psycopg2.sql模块拼接。 - 提交效率极低:每插入一条数据就执行一次
commit(),会大幅增加IO开销,插入速度极慢。 - 冗余读取:同一份CSV文件你先后用pandas、普通open、with open读取了三次,完全没必要。
修正后的代码
import psycopg2 from psycopg2 import sql import pandas as pd # 建立数据库连接 connection = psycopg2.connect(host=host, port=port, dbname=dbname, user=name_user, password=password) cursor = connection.cursor() # 获取用户输入的表名、CSV路径 table_name = self.dlg.comboBox.currentText().strip() csv_path = self.dlg.lineEdit_5.text() self.dlg.lineEdit_6.setText(str(table_name)) # 读取CSV并获取列名 csv_df = pd.read_csv(csv_path) csv_columns = [col.strip() for col in csv_df.columns.values] # 转换为适合批量插入的元组列表 insert_values = [tuple(row) for row in csv_df.to_numpy()] # 构造动态插入SQL # 注意:这里默认CSV列名和表列名完全一致,如果需要匹配可以先查询表的列名校验 sql_insert = sql.SQL("INSERT INTO {} ({}) VALUES ({})").format( sql.Identifier(table_name), sql.SQL(', ').join(map(sql.Identifier, csv_columns)), sql.SQL(', ').join([sql.Placeholder()] * len(csv_columns)) ) # 批量插入 try: cursor.executemany(sql_insert, insert_values) connection.commit() except Exception as e: connection.rollback() raise e finally: cursor.close() connection.close()
额外注意事项
- 如果CSV的列和表的列顺序不一致、或者存在多余列,可以先查询目标表的列名,过滤出两者共有的列再插入,避免列不匹配报错。
- 表名如果属于指定schema,需要在构造
sql.Identifier的时候加上schema名,比如sql.Identifier('schema_name', table_name)。
内容的提问来源于stack exchange,提问作者vigna purohit
相关产品推荐
相关产品推荐

