我必须为postgresql构建一个动态更新查询。 它的动态,因为事先我必须确定要更新的列。
给出样本表:
create table foo (id int, a int, b int, c int)
然后我将以编程方式构建" set"条款
_set = {}
_set['a'] = 10
_set['c'] = NULL
之后我必须构建更新查询。在这里,我被困住了。 我必须构造这个sql Update命令:
update foo set a = 10, b = NULL where id = 1
如何使用psycopg2参数化命令执行此操作? (即如果它不为空则循环遍历dict并构建set子句)?
更新
在我睡觉的时候,我自己找到了解决方案。它是动态的,正是我想要的: - )
create table foo (id integer, a integer, b integer, c varchar)
updates = {}
updates['a'] = 10
updates['b'] = None
updates['c'] = 'blah blah blah'
sql = "upgrade foo set %s where id = %s" % (', '.join("%s = %%s" % u for u in updates.keys()), 10)
params = updates.values()
print cur.mogrify(sql, params)
cur.execute(sql, params)
结果是我需要的内容和方式(尤其是可空和可引用的列):
"upgrade foo set a = 10, c = 'blah blah blah', b = NULL where id = 10"
答案 0 :(得分:4)
使用the alternative column-list syntax:
实际上有一种更简洁的方法sql_template = "UPDATE foo SET ({}) = %s WHERE id = {}"
sql = sql_template.format(', '.join(updates.keys()), 10)
params = (tuple(addr_dict.values()),)
print cur.mogrify(sql, params)
cur.execute(sql, params)
答案 1 :(得分:4)
使用psycopg2.sql – SQL字符串组成模块
该模块包含有用的对象和函数,以方便,安全的方式动态生成SQL。
from psycopg2 import connect, sql
conn = connect("dbname=test user=postgres")
upd = {'name': 'Peter', 'age': 35, 'city': 'London'}
ref_id = 12
sql_query = sql.SQL("UPDATE people SET {data} WHERE id = {id}").format(
data=sql.SQL(', ').join(
sql.Composed([sql.Identifier(k), sql.SQL(" = "), sql.Placeholder(k)]) for k in upd.keys()
),
id=sql.Placeholder('id')
)
upd.update(id=ref_id)
with conn:
with conn.cursor() as cur:
cur.execute(sql_query, upd)
conn.close()
在关闭连接之前运行print(sql_query.as_string(conn))
会显示以下输出:
UPDATE people SET "name" = %(name)s, "age" = %(age)s, "city" = %(city)s WHERE id = %(id)s
答案 2 :(得分:1)
不需要动态SQL。假设a
不可为空,b
可以为空。
如果您要同时更新a
和b
:
_set = dict(
id = 1,
a = 10,
b = 20, b_update = 1
)
update = """
update foo
set
a = coalesce(%(a)s, a), -- a is not nullable
b = (array[b, %(b)s])[%(b_update)s + 1] -- b is nullable
where id = %(id)s
"""
print cur.mogrify(update, _set)
cur.execute(update, _set)
输出:
update foo
set
a = coalesce(10, a), -- a is not nullable
b = (array[b, 20])[1 + 1] -- b is nullable
where id = 1
如果您想更新无:
_set = dict(
id = 1,
a = None,
b = 20, b_update = 0
)
输出:
update foo
set
a = coalesce(NULL, a), -- a is not nullable
b = (array[b, 20])[0 + 1] -- b is nullable
where id = 1
答案 3 :(得分:0)
不使用python格式的选项,使用psycopg2的AsIs
函数作为列名(尽管这不会阻止您对列名进行SQL注入)。字典命名为data
:
update_statement = f'UPDATE foo SET (%s) = %s WHERE id_column=%s'
columns = data.keys()
values = [data[column] for column in columns]
query = cur.mogrify(update_statement, (AsIs(','.join(columns)), tuple(values), id_value))