使用psycopg2时.format为字符串额外添加引号的问题求助
解决Python+psycopg2导出PostgreSQL多表到CSV时的引号/变量问题
看起来你遇到的问题是用str.format()拼接SQL语句时,路径字符串被额外添加了引号,导致COPY命令执行失败。这其实是因为直接用字符串格式化处理SQL标识符(表名)和文件路径时,既容易引发SQL注入风险,又会因为特殊字符(比如路径里的空格)导致引号处理混乱。下面给你两种靠谱的解决方案,完美适配多表遍历的需求:
方案一:用psycopg2的sql模块安全构建SQL(服务器端COPY)
如果你的CSV文件要导出到PostgreSQL服务器能访问的路径,推荐用这种方式,它能正确处理表名和路径的引号问题:
import psycopg2 from psycopg2 import sql # 数据库连接配置(根据你的实际情况修改) conn_params = { "dbname": "your_database", "user": "your_user", "password": "your_password", "host": "localhost" } # 要处理的表名数组 tables_to_export = ["table_a", "table_b", "table_c"] # 基础输出路径(注意用原始字符串r""避免转义问题) base_output_path = r"C:\Administrator File\" with psycopg2.connect(**conn_params) as conn: with conn.cursor() as cur: for table in tables_to_export: # 生成每个表对应的CSV文件名 csv_file_path = f"{base_output_path}{table}.csv" # 转义路径里的单引号,避免破坏SQL语句 escaped_path = csv_file_path.replace("'", "''") # 用sql.Identifier处理表名(安全引用标识符),sql.Literal处理路径字符串 copy_query = sql.SQL("COPY {} TO '{}' WITH (FORMAT CSV, HEADER);").format( sql.Identifier(table), sql.Literal(escaped_path) ) cur.execute(copy_query) conn.commit() print(f"成功导出表 {table} 到 {csv_file_path}")
方案二:用客户端copy_to导出(本地CSV)
如果你的CSV要导出到本地机器(客户端),推荐用cur.copy_to()方法,这种方式不需要自己拼接COPY SQL,彻底避开引号问题:
import psycopg2 conn_params = { "dbname": "your_database", "user": "your_user", "password": "your_password", "host": "localhost" } tables_to_export = ["table_a", "table_b", "table_c"] base_output_path = r"C:\Administrator File\" with psycopg2.connect(**conn_params) as conn: with conn.cursor() as cur: for table in tables_to_export: csv_file_path = f"{base_output_path}{table}.csv" # 打开本地文件,用copy_to直接写入 with open(csv_file_path, "w", newline="", encoding="utf-8") as csv_file: cur.copy_to(csv_file, table, sep=",", header=True) print(f"成功导出表 {table} 到本地文件 {csv_file_path}")
为什么你的原方法会出错?
当你用str.format()直接拼接路径时,如果路径里有空格或者特殊字符,格式化后的SQL会出现引号嵌套或不匹配的情况。比如你的fullTempBaseURL包含空格,format()后可能会生成类似COPY my_table TO ''C:\Administrator File\output.csv''...的错误语句(额外的引号),导致PostgreSQL无法识别路径。而上面的两种方案,要么用psycopg2官方推荐的SQL构建方式处理标识符和字符串,要么直接绕过SQL拼接,彻底解决引号问题。
内容的提问来源于stack exchange,提问作者Jonnyboy




