【问题标题】:Add filters to query dynamically using pyscopg2添加过滤器以使用 psycopg2 动态查询
【发布时间】:2019-05-28 22:03:32
【问题描述】:

试图创建一个动态过滤器,我在打印没有“引号”的 where 语句时遇到了困难。

输出:select "col1", "col2" from "table1" where "col2=1234" and "col3=column1"

所需:select "col1", "col2" from "table1" where col2="1234" and col3="column1"

def filter(table,*args,**kwarg):
 query = sql.SQL("select {0} from {1} where {2}").format(
    sql.SQL(', ').join(map(sql.Identifier,[arg for arg in args])),
    sql.Identifier(table),
    sql.SQL(' and ').join(map(sql.Identifier,{(str(k)+'='+str(v)) for k,v in kwarg.iteritems()}))
    )
 print query.as_string(Connection())

【问题讨论】:

    标签: python sql psycopg2


    【解决方案1】:

    您将每个条件编码为单个 SQL 标识符 - 即,您实际上是在编码 sql.Identifier('foo=bar')

    另一个陷阱是您将查询值直接放在 SQL 中;虽然你可能相信消息来源, 一般来说,这将是一个坏主意。更好的是使用占位符,并提供实际值 在执行时。

    最后 - 列表推导通常比 map 更受欢迎;不过,这是一种风格选择。

    将它们放在一起,谓词将正确呈现如下内容:

    def filter(table, *args, **kwargs):
      conditions = [sql.SQL(' = ').join([sql.Identifier(k), sql.Placeholder()]) for k in kwarg.keys()]
      query = sql.SQL("select {0} from {1} where {2}").format(
         sql.SQL(', ').join([sql.Identifier(arg) for arg in args]),
         sql.Identifier(table),
         sql.SQL(' and ').join(conditions)
      )
    

    这确实假设底层字典在查询构造和执行之间没有被修改。您的“执行”将类似于:

    cursor.execute(sql, kwargs.values())
    

    如果该假设不成立,请将conditions 理解中的sql.Placeholder() 替换为sql.Literal(v),并使用kwargs.items() 代替kwargs.keys()。在这种情况下,我认为Literal 可以正确转义几乎所有有风险的字符串,但使用占位符和参数更安全。

    希望有帮助

    【讨论】:

      猜你喜欢
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      • 1970-01-01
      • 1970-01-01
      • 2020-03-14
      • 2021-02-26
      相关资源
      最近更新 更多