【问题标题】:Getting error: ValueError: unsupported format character: '('出现错误:ValueError:不支持的格式字符:'('
【发布时间】:2021-01-16 17:08:26
【问题描述】:

我有以下函数用于动态生成 SQL 查询,以使用 psycopg2 在 postgres 中插入 pandas 数据帧。我将使用此函数插入​​多个数据帧,这些数据帧可能没有数据库中的所有列,因此我不使用 pandas.to_sql()。 我不断收到错误 ValueError: unsupported format character: '(' 并且不知道是什么原因造成的。

任何帮助将不胜感激。

def execute_values(conn, df, schema, table):
    """
    Using psycopg2.extras.execute_values() to insert the dataframe
    """
    
    # Create a tuple of dicts from the dataframe values
    dicts = tuple(df.to_dict('records'))

    columns = sql.SQL(',').join(map(sql.Identifier, list(df.columns)))
    values = sql.SQL(',').join(map(sql.Placeholder, list(df.columns)))

    # SQL query to execute
    query = sql.SQL('INSERT INTO {} ({}) VALUES ({})').format(
        sql.Identifier(schema, table),
        columns,
        values
    )
    
    cursor = conn.cursor()
    try:
        extras.execute_values(cursor, query, dicts)
        conn.commit()
    except (Exception, psycopg2.DatabaseError) as error:
        print("Error: %s" % error)
        conn.rollback()
        cursor.close()
        raise

    print("execute_values() done")
    cursor.close() 

【问题讨论】:

  • 如果我关注这个 INSERT INTO {} ({}) .. 应该是 INSERT INTO {}.{} ({})... 。并且sql.Identifier() 需要拆分为一个用于架构和一个用于表。
  • @AdrianKlaver 根据 psycopg 文档 (psycopg.org/docs/sql.html):可以将多个字符串传递给对象以表示限定名称,即以点分隔的标识符序列。示例:query = sql.SQL("select {} from {}").format( sql.Identifier("table", "field"), sql.Identifier("schema", "table")) print(query.as_string(conn)) select "table"."field" from "schema"."table"
  • 你使用的是什么版本的psycopg2?
  • @AdrianKlaver psycopg2 v2.8.6
  • 嗯,这已经够新了。那么接下来的嫌疑人是columns和values。在两者上尝试print() 以查看实际存在的内容。看看 schema 和 table 传递的内容也不会有什么坏处。

标签: postgresql psycopg2


【解决方案1】:

如何使用execute_values制作动态SQL:

import psycopg2
from psycopg2.extras import execute_values
from psycopg2 import sql

con = psycopg2.connect("dbname=test host=localhost user=aklaver")
cur = con.cursor()

columns = sql.SQL(',').join(map(sql.Identifier, ['id', 'cond', 'animal']))

data_dict = [{"id": 20, "cond": "fair", "animal": "fish"}, {"id": 30, "cond": "poor", "animal": "fish"}, {"id": 40, "cond": "great", "animal": "fish"}]


values = sql.SQL(',').join(map(sql.Placeholder, ['id', 'cond', 'animal']))
# Since you are using a dict you need to provide a template for 
# execute_values
values_template = sql.SQL('(') + values + sql.SQL(')')

print(values_template.as_string(con))                                                                                                                                     (%(id)s,%(cond)s,%(animal)s)


insert_sql = sql.SQL("INSERT INTO {} ({}) VALUES %s").format(sql.Identifier("animals"), columns)

print(insert_sql.as_string(con))
INSERT INTO "animals" ("id","cond","animal") VALUES %s

execute_values(cur, insert_sql, data_dict, template=values_template)
con.commit()

 select * from animals ;
 id | cond  | animal 
----+-------+--------
 20 | fair  | fish
 30 | poor  | fish
 40 | great | fish

【讨论】:

  • 谢谢!这很好用。只是出于好奇,您将使用什么来执行我的查询而不是 execute_values?因为我从 psycopg2 docs 得到了我的查询。
  • 这实际上取决于您使用的数据量。您还可以选择使用execute_batch,这将使用您最初构建的查询,但通过一些page_size 对语句进行批处理。如果您要处理要插入到表中的大量数据,那么COPY 是最佳性能选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 2021-06-06
  • 2013-08-02
  • 1970-01-01
相关资源
最近更新 更多