postgresql 在psycopg3中插入多行

omjgkv6w  于 2024-01-07  发布在  PostgreSQL
关注(0)|答案(2)|浏览(153)

我曾经在psycopg2中使用execute_values,但在psycopg3中没有了。我尝试遵循this answer或此github post中的建议,但它似乎不适用于我的用例。我试图插入多个值,我的SQL是这样的:

sql = INSERT INTO activities (type_, key_, a, b, c, d, e)
        VALUES %s
        ON CONFLICT (key_) DO UPDATE
        SET
            a = EXCLUDED.a,
            b = EXCLUDED.b,
            c = EXCLUDED.c,
            d = EXCLUDED.d,
            e = EXCLUDED.e
values = [['type', 'key', None, None, None, None, None]]

字符串
但是执行cursor.executemany(sql, values)的结果是{ProgrammingError}the query has 1 placeholder but 7 parameters were passed。我尝试了很多带有额外括号的变体,但总是会导致一些错误。例如,执行self.cursor.executemany(sql, [values])的结果是syntax error near or at "$1": Line 3: VALUES $1

cbwuti44

cbwuti441#

values子句应该由一个%s占位符组成,用于插入的每一列,用逗号分隔,所有内容都放在括号内,如下所示:

INSERT INTO t (a, b, c) VALUES (%s, %s, %s)

字符串
我们可以通过字符串操作生成所需的字符串:

# Create one placeholder per column inserted.
placeholders = ', '.join(['%s'] * len(values[0]))
# Wrap in parentheses.
values_clause =  f"""({placeholders})"""
# Inject into the query string.
isql = isql % values_clause

with psycopg.connect(dbname='test') as conn, conn.cursor() as cur:
    cur.executemany(isql, values)
    conn.commit()


然而,psycopg提供了tools来组合SQL语句,如果你的查询构建是非常动态的,使用这些工具可能比依赖字符串操作更安全。使用这些工具,你会得到这样的结果(这次我在主查询字符串中添加了括号,因为不这样做没有好处):

placeholders = sql.SQL(', ').join(sql.Placeholder() * len(values[0]))
isql = sql.SQL("""INSERT INTO t77716028 (type_, key_, a, b, c, d, e)
        VALUES ({placeholders})
        ON CONFLICT (key_) DO UPDATE
        SET
            a = EXCLUDED.a,
            b = EXCLUDED.b,
            c = EXCLUDED.c,
            d = EXCLUDED.d,
            e = EXCLUDED.e""")
isql = isql.format(placeholders=placeholders)

with psycopg.connect(dbname='test') as conn, conn.cursor() as cur:
    print(f'{isql.as_string(conn)=}')
    cur.executemany(isql, values)
    conn.commit()

trnvg8h3

trnvg8h32#

我建议将参数序列化并作为JSON传递。
SQL和values会这样传递:

INSERT INTO activities (type_, key_, a, b, c, d, e)
VALUES (
  %(arg)s::json->>'type', %(arg)s::json->>'key', 
  %(arg)s::json->>'a', %(arg)s::json->>'b',
  %(arg)s::json->>'c', %(arg)s::json->>'d', %(arg)s::json->>'e'
) 
ON CONFLICT (key_) DO UPDATE SET
  a = EXCLUDED.a, b = EXCLUDED.b, c = EXCLUDED.c, d = EXCLUDED.d, e = EXCLUDED.e;

values = {'arg':json.dumps({'type':'type','key':'key','a':None,'b':None,'c':None,'d':None,'e':None})}

字符串
请注意,由于->>运算符产生text,因此可能需要进行一些类型转换。相同的方法可以在不同的场景中成功使用。仍然可以使用预处理语句,从而检查SQL注入的风险。

相关问题