【问题标题】:Python, MySQLdb and escaping table names?Python、MySQLdb 和转义表名?
【发布时间】:2011-09-30 21:26:02
【问题描述】:

我可能遗漏了一些明显的东西,但我无法弄清楚我的代码与我在 MySQLdb 的在线文档中看到的各种示例有何不同。

我对 python 编程相当陌生,对 perl 更有经验。我想要做的是尽早养成某些好习惯(就像在 perl 中我总是从“使用严格;使用警告”开始),所以我试图确保我在一个独立的文件中创建可重用的函数( funct.py) 以节省我以后的时间。

我有这个从表中选择随机行的函数:

def returnRandom(conn,countcol,table,field):
    cursor = conn.cursor()
    cursor.execute('SELECT MAX(%s) FROM %s',(countcol,table))
    maxRow = cursor.fetchone()[0]
    cursor.execute("SELECT MIN(%s) FROM %s",(countcol,table))
    minRow = cursor.fetchone()[0]
    randomId = random.randrange(minRow,maxRow+1,1)
    cursor.execute("SELECT ? FROM ? WHERE id >=? LIMIT 1",field,table,randomId)
    return cursor.fetchone()[0]

它是这样称呼的:

msg = funct.returnRandom(conn,"id","testtable","data")

不幸的是,它出错了: _mysql_exceptions.ProgrammingError: (1064, "您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 ''testtable'' 附近使用正确的语法")

如果我将 testtable 放在执行行上的 %s 的位置,查询将运行,但看起来它正在运行

SELECT MAX('id') FROM testtable;

当然会返回“id”。

考虑到这两个,它看起来像是在尝试执行它们时引用了 %s 条目。我想知道是否有人可以解释我如何让它停止这样做,或者我应该如何真正做我想要实现的目标?我希望函数尽可能通用,因此依赖于在调用时传递给它的数据。

编辑:我应该添加,如果我替换 ?标记:

....
    cursor.execute('SELECT MAX(?) FROM ?',(countcol,table))
File "/usr/lib/pymodules/python2.7/MySQLdb/cursors.py", line 151, in execute
    query = query % db.literal(args)
TypeError: not all arguments converted during string formatting

【问题讨论】:

    标签: python mysql-python


    【解决方案1】:

    您不能将 DB-API 用于元数据;您需要在execute() 呼叫之外自行更换。

    query = 'SELECT MAX(%%s) FROM `%s`' % (table,)
    cursor.execute(query, (countcol,))
    

    如果table 来自外部来源,您显然不应该这样做。

    【讨论】:

    • 这是我想要避免的理想情况。我已经使用 format 函数实现了类似的功能,但我想更安全一点。
    【解决方案2】:

    MySQLdb 可能用单引号而不是反引号引用您的表名。试试这个

    cursor.execute('SELECT MAX(%%s) FROM `%s`' % table,(countcol))
    

    【讨论】:

    • 不,那也失败了,现在还在寻找 database.'table' !
    • 这个答案与@Ignacio 的基本相同。我不确定你怎么会得到引号。您是否在带引号的字符串末尾处在 %s 周围输入了反引号?
    【解决方案3】:

    有趣。但是在manual 中有几个例子。也许是类似的东西。

    c=db.cursor()
    max_price=5
    c.execute("""SELECT spam, eggs, sausage FROM breakfast
              WHERE price < %s""", (max_price,))
    

    在本例中,max_price=5 那么为什么在字符串中使用 %s?因为 MySQLdb 会将其转换为 SQL 文字值,即字符串 '5'。完成后,查询实际上会说“...WHERE price

    还有

    c.executemany(
          """INSERT INTO breakfast (name, spam, eggs, sausage, price)
          VALUES (%s, %s, %s, %s, %s)""",
          [
          ("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ),
          ("Not So Much Spam Plate", 3, 2, 0, 3.95 ),
          ("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 )
          ] )
    

    在这里,我们插入三行,每行五个值。注意有 混合类型(字符串、整数、浮点数),尽管我们仍然只使用 %s。 另请注意,我们仅包含一行的格式字符串。 MySQLdb 挑选出来并为每一行复制它们。

    【讨论】:

    • 问题是转义表名,而不是列值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 2015-01-20
    • 2011-11-10
    • 2011-11-14
    相关资源
    最近更新 更多