我需要用一个查询插入多行(行数不是常量),所以我需要像这样执行查询:
INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);
我唯一知道的办法就是
args = [(1,2), (3,4), (5,6)]
args_str = ','.join(cursor.mogrify("%s", (x, )) for x in args)
cursor.execute("INSERT INTO t (a, b) VALUES "+args_str)
但我想要更简单的方法。
来自Psycopg2教程页面Postgresql.org的一个片段(见底部):
我想向您展示的最后一项是如何使用字典插入多行。如果你有以下情况:
namedict = ({"first_name":"Joshua", "last_name":"Drake"},
{"first_name":"Steven", "last_name":"Foo"},
{"first_name":"David", "last_name":"Bar"})
你可以很容易地将这三行都插入到字典中:
cur = conn.cursor()
cur.executemany("""INSERT INTO bar(first_name,last_name) VALUES (%(first_name)s, %(last_name)s)""", namedict)
它没有节省多少代码,但它确实看起来更好。
几年来,我一直在使用ant32的答案。然而,我发现它在python 3中抛出了一个错误,因为mogrify返回一个字节字符串。
显式转换为bytse字符串是使代码与python 3兼容的简单解决方案。
args_str = b','.join(cur.mogrify("(%s,%s,%s,%s,%s,%s,%s,%s,%s)", x) for x in tup)
cur.execute(b"INSERT INTO table VALUES " + args_str)
另一种有效的方法是将rows作为1参数传递给insert,
也就是数组的json对象。
例如,你传递的论点:
[ {id: 18, score: 1}, { id: 19, score: 5} ]
它是一个数组,其中可以包含任意数量的对象。
然后你的SQL看起来像这样:
INSERT INTO links (parent_id, child_id, score)
SELECT 123, (r->>'id')::int, (r->>'score')::int
FROM unnest($1::json[]) as r
注意:你的postgress必须足够新,才能支持json