【问题标题】:Python SQLite how to get SQL string statement being executedPython SQLite如何获取正在执行的SQL字符串语句
【发布时间】:2012-11-30 13:55:12
【问题描述】:

假设我们有一个 SQL 语句,它只需要在对 DB 执行之前使用参数完成。例如:

sql = '''
      SELECT  id, price, date_out
      FROM sold_items
      WHERE date_out BETWEEN ? AND ?
      '''

database_cursor.execute(sql, (start_date, end_date))

如何获取解析并执行的字符串?,如下所示:

SELECT  id, price, date_out
FROM sold_items
WHERE date_out BETWEEN 2010-12-05 AND 2011-12-01

在这个简单的情况下,它不是很重要,但是我还有其他更复杂的 SQL 语句,出于调试目的,我想自己在我的 sqlite 管理器中执行它们并检查结果。

提前致谢

【问题讨论】:

  • 您不想自己构建字符串的任何具体原因?
  • 我在某处读到最好使用替换方法。不记得为什么。
  • 据称,担心的是SQL注入。我猜如果你想调试你的查询,它还没有投入生产,所以你真的需要担心吗?
  • 它是保存(搜索:sql injection),在某些情况下,数据库能够“重用”带有其他参数的查询,而它必须对全新的查询做更多的工作跨度>
  • 我猜它还会在需要时为字符串添加“...”。事实是,我想避免为以后的生产重构代码。此外,正如 Argeman 所指出的,在某些情况下,将查询结构与数据分开是很有趣的。

标签: python sql sqlite


【解决方案1】:

更新。我从this web page 了解到,从 Python 3.3 开始,您可以触发打印已执行的 SQL

connection.set_trace_callback(print)

如果您想恢复到静默处理,请使用

connection.set_trace_callback(None)

您可以使用其他函数代替print

【讨论】:

    【解决方案2】:

    SQLite 实际上从不将参数替换为 SQL 查询字符串本身;执行命令时直接读取参数值。 (格式化这些值只是为了再次将它们解析为相同的值将是无用的开销。)

    但是如果你想知道参数在 SQL 中是如何写的,你可以使用quote function;像这样:

    import re
    def log_and_execute(cursor, sql, *args):
        s = sql
        if len(args) > 0:
            # generates SELECT quote(?), quote(?), ...
            cursor.execute("SELECT " + ", ".join(["quote(?)" for i in args]), args)
            quoted_values = cursor.fetchone()
            for quoted_value in quoted_values:
                s = s.replace('?', quoted_value, 1)
                #s = re.sub(r'(values \(|, | = )\?', r'\g<1>' + quoted_value, s, 1)
        print "SQL command: " + s
        cursor.execute(sql, args)
    

    (如果? 不是参数,即在文字字符串中,则此代码将失败。除非您使用 re.sub 版本,否则它将仅匹配 ? 在 'values (' ', ' 或 ' = '。'\g' 将文本放回 ? 之前,使用 '\g' 可避免与以数字开头的quoted_values 发生冲突。)

    【讨论】:

    • 看起来有点像我想要的,但我并没有真正让它工作?也许是一个更具体的例子?提前致谢
    • sn-p有错误,该行应该是:cursor.execute("SELECT " + ", ".join(["quote(?)" for i in args]), args)
    【解决方案3】:

    我写了一个函数,它只用参数填充问号。

    奇怪的是,每个人都向您发送使用位置参数的方向,但没有人考虑需要记录或预览或检查全部查询。

    无论如何,下面的代码假设

    • 没有'?'查询中不用作后置参数标记的标记。我不确定是否总是这样。
    • 参数的值将用引号括起来。例如,当您为表名使用参数时,情况就不是这样了。不过,这种用例不太可能。
        def compile_query(query, *args):
            # test for mismatch in number of '?' tokens and given arguments
            number_of_question_marks = query.count('?')
            number_of_arguments = len(args)
    
            # When no args are given, an empty tuple is passed
            if len(args) == 1 and (not args[0]):
                number_of_arguments = 0
            
            if number_of_arguments != number_of_question_marks:
                return f"Incorrect number of bindings supplied. The current statement uses {number_of_question_marks}, and there are {number_of_arguments} supplied."
    
            # compile query
            for a in args:
                query = query.replace('?', "'"+str(a)+"'", 1)
    
            return query
    

    建议用法

    query = "INSERT INTO users (name, password) VALUES (?, ?)"
    
    # sensitive query, we need to log this for security
    query_string = compile_query(query, username, password_hash)
    fancy_log_function(query_string)
    
    # execute
    cursor.execute(query, username, password_hash)
    

    【讨论】:

      【解决方案4】:

      字符串格式化呢?

      sql = """
        SELECT  id, price, date_out
        FROM sold_items
        WHERE date_out BETWEEN {0} AND {1} """.format(start_date, end_date)
        """
      database_cursor.execute(sql)
      

      【讨论】:

      • 这是我想要避免的。无论如何感谢您的评论。
      猜你喜欢
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多