【问题标题】:Python adds single quote to my query parametersPython 在我的查询参数中添加单引号
【发布时间】:2020-01-31 16:28:10
【问题描述】:

我正在尝试执行这个查询:

SELECT '23.34.67.0/22' CONCAT(DAY_31, 'hello') DAY_31 FROM Jule

使用 pymysql。我的代码是:

cursor.execute("SELECT %s CONCAT(%s, %s) %s FROM Jule", (p, 'DAY_' + _day, as_tmp, 'DAY_' + _day))

但是python添加单引号并返回语法错误

“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 '('DAY_31', 'hello') 'DAY_31' FROM Jule' 附近使用正确的语法”

DAY_31 是 Jule Schema 的一列

【问题讨论】:

  • 你检查字符串转义了吗? this 问题是否为您指明了正确的方向?我所说的字符串转义的意思是,似乎对您的字符串进行了自动不需要的转义,并且可能有一种方法可以在 cursor.execute func 中避免这种情况。
  • 它返回“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以了解在 '('\\'DAY_31\\'', ' 附近使用的正确语法6762') '\\'DAY_31\\'' FROM Jule' 在第 1 行"
  • 好的,缺少逗号'cursor.execute("SELECT %s, CONCAT(%s, %s) %s FROM Jule", (p, 'DAY_' + day, as_tmp , 'DAY' + _day))
  • 不应该是:SELECT '23.34.67.0/22', CONCAT(DAY_31, 'hello'), DAY_31 FROM Jule,也就是说你不是少了逗号吗?

标签: python mysql quotes pymysql


【解决方案1】:

如果没记错的话,? 代替 %s 可能会成功。

【讨论】:

  • 感谢您的回答,但它返回'TypeError:字符串格式化期间并非所有参数都转换'
【解决方案2】:

您最终使用引号的原因是cursor.execute 在您作为参数传入的值周围添加了这些。这完全适合您的第二个参数,因为如果将值“hello”按原样插入到查询中,您最终会得到这样的查询:

 SELECT '23.34.67.0/22' CONCAT(DAY_31, hello) DAY_31 FROM Jule

您会收到错误消息,告诉您 MySQL 无法识别 hello 应指的内容。

但显然,这不适用于您想要传入 字段名称 或查询的任何其他不是原始字符串值的部分的情况。在这些情况下,您需要在执行查询之前将它们拼接到您的字符串中。一种方法是使用f-strings,但也有其他选择。这是您的 cursor.execute 行,其中字段名称使用 f 字符串拼接:

cursor.execute(f"SELECT %s, CONCAT({'DAY_'+_day}, %s) {'DAY_'+_day} FROM Jule", (p, as_tmp))

请注意,我也已从参数列表中删除了 'DAY_'+_day

重要提示:

虽然这应该像这样工作(尽管我认为您还需要在 SELECT '23.34.67.0/22' 之后添加一个额外的逗号,这是我在上面的示例中添加的),但如果 day 具有源自外部的值,这一点非常重要您的应用程序(例如,由用户在表单字段中传递),在将其拼接到您的查询之前,请确保它完全符合您想要的格式。 Checking that the string value is an integer 可能是一种方法。这很重要的原因是,如果没有这个,您的应用程序可能容易出现SQL injection,这可能会允许用户在您的数据库上运行任意 SQL。如果day 的值仅由您的应用程序计算,则您无需担心这一点。

【讨论】:

    【解决方案3】:

    实际上发生的事情与cursor.execute无关。这正是您在 python 中格式化字符串的方式。

    我们首先应该注意 %s %d 可以是特定于 SQL 的,并且这些也可以在 python 中用于字符串格式化。

    因此,考虑到这一点,我认为您无需使用 %s 进行字符串格式化(这对可读性没有帮助)。而且由于您是cursor.execute直接访问您的数据库,因此您可以直接在 python 中格式化您的字符串。

    小检查看看发生了什么:

    p = "23.34.67.0/22"
    as_tmp = "hello"
    _day = "3"
    print("SELECT %s CONCAT(%s, %s) %s FROM Jule", (p, 'DAY_' + _day, as_tmp, 'DAY_' + _day))
    # output
    # SELECT %s CONCAT(%s, %s) %s FROM Jule ('23.34.67.0/22', 'DAY_3', 'hello', 'DAY_3')
    # ^^^^ so this is what is being sent in cursor.execute (with all the quotes and so on)
    

    如果你用 f 字符串格式化,你会增加可读性,你应该摆脱引号的问题

    print(f"SELECT '{p}' CONCAT(DAY_{_day}, '{as_tmp}') DAY_{_day} FROM Jule")
    # output
    # SELECT '23.34.67.0/22' CONCAT(DAY_3, 'hello') DAY_3 FROM Jule
    

    所以解决办法是:

    cursor.execute(f"SELECT '{p}' CONCAT(DAY_{_day}, '{as_tmp}') DAY_{_day} FROM Jule")
    

    【讨论】:

    • 感谢您的回答,但问题是缺少逗号。无论如何我会记住你的回答
    • 如果as_tmp 可能来自应用程序外部,则此答案会使应用程序容易受到 SQL 注入的影响。原始方法对于字符串数据值很好,但是没有办法避免像您建议的那样拼接字段名称。
    猜你喜欢
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    相关资源
    最近更新 更多