在psycopg2中建立动态更新查询

Gab*_*bor 9 python postgresql psycopg2

我必须为postgresql构建一个动态更新查询。它是动态的,因为事先我必须确定要更新的列。

给定一个示例表:

create table foo (id int, a int, b int, c int)
Run Code Online (Sandbox Code Playgroud)

然后,我将以编程方式构造“ set”子句

_set = {}
_set['a'] = 10
_set['c'] = NULL
Run Code Online (Sandbox Code Playgroud)

之后,我必须构建更新查询。在这里我被卡住了。我必须构造此sql Update命令:

update foo set a = 10, b = NULL where id = 1
Run Code Online (Sandbox Code Playgroud)

如何使用psycopg2参数化命令执行此操作?(即遍历字典,如果它不为空并建立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)
Run Code Online (Sandbox Code Playgroud)

结果是我需要什么以及如何使用(尤其是可为空和可引用的列):

"upgrade foo set a = 10, c = 'blah blah blah', b = NULL where id = 10"
Run Code Online (Sandbox Code Playgroud)

Rma*_*att 7

实际上,使用替代的column-list语法有一种更简洁的方法:

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)
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但我也建议对ID值也使用`%s`,以便您可以防止使用psycopg2进行sql注入-以防万一该值来自某个未知客户端 (2认同)

小智 5

使用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()
Run Code Online (Sandbox Code Playgroud)

print(sql_query.as_string(conn))在关闭连接之前运行将显示以下输出:

UPDATE people SET "name" = %(name)s, "age" = %(age)s, "city" = %(city)s WHERE id = %(id)s
Run Code Online (Sandbox Code Playgroud)


Clo*_*eto 1

不需要动态 SQL。假设a不可为空并且b可以为空。

如果您想同时更新ab

_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)
Run Code Online (Sandbox Code Playgroud)

输出:

update foo
set
    a = coalesce(10, a), -- a is not nullable
    b = (array[b, 20])[1 + 1] -- b is nullable
where id = 1
Run Code Online (Sandbox Code Playgroud)

如果您不想更新:

_set = dict(
    id = 1,
    a = None,
    b = 20, b_update = 0
)
Run Code Online (Sandbox Code Playgroud)

输出:

update foo
set
    a = coalesce(NULL, a), -- a is not nullable
    b = (array[b, 20])[0 + 1] -- b is nullable
where id = 1
Run Code Online (Sandbox Code Playgroud)