【问题标题】:Passing list of parameters to SQL in psycopg2在 psycopg2 中将参数列表传递给 SQL
【发布时间】:2012-01-30 02:21:28
【问题描述】:

我有一个要从数据库中获取的行 ID 列表。我正在使用 python 和 psycopg2,我的问题是如何有效地将这些 id 传递给 SQL?我的意思是,如果我知道该列表的长度,这很容易,因为我总是可以根据需要手动或自动将尽可能多的“%s”表达式添加到查询字符串中,但在这里我不知道我需要多少.重要的是我需要使用 sql "id IN (id1, id2, ...)" 语句选择这些行。我知道可以检查列表的长度并将合适数量的“%s”连接到查询字符串中,但恐怕它会非常缓慢和丑陋。有谁知道如何解决它?请不要问我为什么需要用“IN”语句来做这件事——这是一个基准,是我课堂作业的一部分。提前致谢!

【问题讨论】:

  • 你反对 SQL 答案吗?使用动态 SQL,您可以给出任意长度的字符串并让 SQL 正确读取它。

标签: python postgresql psycopg2


【解决方案1】:

Python 元组在 psycopg2 中被转换为 sql 列表:

cur.mogrify("SELECT * FROM table WHERE column IN %s;", ((1,2,3),))

会输出

'SELECT * FROM table WHERE column IN (1,2,3);'

对于 Python 新手:不幸的是,在这里使用元组而不是列表很重要。这是第二个例子:

cur.mogrify("SELECT * FROM table WHERE column IN %s;", 
    tuple([row[0] for row in rows]))

【讨论】:

  • 谢谢,我没注意到。您的解决方案的唯一问题是您忘记了该元组中的逗号。
  • 请注意,Python LISTS 将转换为 Postgres ARRAY 类型,因此我发现我经常需要在 cursor.execute(...) 参数中执行类似 (tuple(SOME_LIST),) 的操作。请注意我们如何将列表的 tuple() 包装在单个元素文字元组中,因此我们有一个元组的元组,如本例所示。
  • cur.mogrify("SELECT * FROM table WHERE column IN %s;", tuple([row[0] for row in rows])) 这还不清楚。它似乎与前面的示例无关。
【解决方案2】:

这个问题很老了,也许还有一个更新的问题,但我的同事们现在的答案是:

sql = "SELECT * FROM table WHERE column = ANY(%(parameter_array)s)"
cur.execute(sql,{"parameter_array": [1, 2, 3]})

【讨论】:

  • 这适用于我必须使用$1 而不是%s 而接受的答案没有的特殊情况。感谢您发布此信息!
【解决方案3】:

现在 psycopg2 (https://www.psycopg.org/docs/sql.html) 的 sql 模块可用于防止错误和注入,例如:

import psycopg2
from psycopg2 import sql

params = config()
conn = psycopg2.connect(**params)
cur = conn.cursor()

ids = ['a','b','c']
sql_query = sql.SQL('SELECT * FROM {} WHERE id IN ({});').format(
                    sql.Identifier('table_name'),
                    sql.SQL(',').join(map(sql.Identifier, ids))
                )
print (sql_query.as_string(cur)) # for debug
cur.execute(sql_query)

from configparser import ConfigParser
def config(filename='database.ini', section='postgresql'):
    # create a parser
    parser = ConfigParser()
    # read config file
    parser.read(filename)

    # get section, default to postgresql
    db = {}
    if parser.has_section(section):
        params = parser.items(section)
        for param in params:
            db[param[0]] = param[1]
    else:
        raise Exception('Section {0} not found in the {1} file'.format(section, filename))

    return db

注意:sql.Identifier 将在需要时添加引号,因此如果您在 PostgreSQL 中使用带引号的标识符也可以使用(它们必须用于允许区分大小写的命名)。

database.ini的例子和结构:

[postgresql]
host=localhost
port=5432
database=postgres
user=user
password=mypass

【讨论】:

    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 2012-11-27
    相关资源
    最近更新 更多