Python MySQL参数化查询

Python MySQL参数化查询,python,mysql,bind-variables,Python,Mysql,Bind Variables,我很难使用MySQLdb模块将信息插入数据库。我需要在表中插入6个变量 cursor.execute (""" INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation) VALUES (var1, var2, var3, var4, var5, var6) """) 有人能帮我解释一下这里的语法吗?链接的文档给出了以下示例: curso

我很难使用MySQLdb模块将信息插入数据库。我需要在表中插入6个变量

cursor.execute ("""
    INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
    VALUES
        (var1, var2, var3, var4, var5, var6)

""")

有人能帮我解释一下这里的语法吗?

链接的文档给出了以下示例:

   cursor.execute ("""
         UPDATE animal SET name = %s
         WHERE name = %s
       """, ("snake", "turtle"))
   print "Number of rows updated: %d" % cursor.rowcount
因此,您只需根据自己的代码对其进行调整-示例:

cursor.execute ("""
            INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
            VALUES
                (%s, %s, %s, %s, %s, %s)

        """, (var1, var2, var3, var4, var5, var6))

(如果SongLength是数字,您可能需要使用%d而不是%s)。

您有几个可用选项。您将希望熟悉python的字符串Iterporation。如果你想知道这样的事情,你将来可能会更成功地搜索这个词

更好的查询:

some_dictionary_with_the_data = {
    'name': 'awesome song',
    'artist': 'some band',
    etc...
}
cursor.execute ("""
            INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
            VALUES
                (%(name)s, %(artist)s, %(album)s, %(genre)s, %(length)s, %(location)s)

        """, some_dictionary_with_the_data)

考虑到您的所有数据可能已经存在于对象或字典中,第二种格式更适合您。另外,当您必须在一年内回来更新此方法时,必须在字符串中计算“%s”的出现次数也很糟糕:)

请注意在SQL查询中使用字符串插值,因为它不会正确地转义输入参数,并且会使您的应用程序存在SQL注入漏洞这一差异看似微不足道,但实际上却是巨大的

不正确(存在安全问题) 正确(带转义)
这增加了一种混淆,即用于绑定SQL语句中参数的修饰符在不同的DB API实现之间有所不同,mysql客户端库使用
printf
样式语法,而不是更普遍接受的“?”标记(由例如
python sqlite
使用)。

实际上,即使您的变量(SongLength)是数字,您仍需使用%s对其进行格式化才能正确绑定参数。如果您尝试使用%d,将出现错误。以下是此链接的一个小摘录:

要执行查询,首先需要一个光标,然后可以对其执行查询:

c=db.cursor()
max_price=5
c.execute("""SELECT spam, eggs, sausage FROM breakfast
          WHERE price < %s""", (max_price,))
c=db.cursor()
最高价格=5
c、 执行(““”从早餐中选择垃圾邮件、鸡蛋、香肠
其中价格<%s”“,(最高价格,)

在本例中,max_price=5为什么要在字符串中使用%s?因为MySQLdb会将其转换为SQL文本值,即字符串“5”。当它完成时,查询实际上会说,“…其中price<5”.

作为所选答案的替代方案,与Marcel的安全语义相同,这里是一种使用Python字典指定值的简洁方法。它的优点是在添加或删除要插入的列时易于修改:

  meta_cols = ('SongName','SongArtist','SongAlbum','SongGenre')
  insert = 'insert into Songs ({0}) values ({1})'.format(
      ','.join(meta_cols), ','.join( ['%s']*len(meta_cols)))
  args = [ meta[i] for i in meta_cols ]
  cursor = db.cursor()
  cursor.execute(insert,args)
  db.commit()
其中,meta是保存要插入的值的字典。可以用相同的方法进行更新:

  meta_cols = ('SongName','SongArtist','SongAlbum','SongGenre')
  update='update Songs set {0} where id=%s'.
        .format(','.join([ '{0}=%s'.format(c) for c in meta_cols ]))
  args = [ meta[i] for i in meta_cols ]
  args.append(songid)
  cursor=db.cursor()
  cursor.execute(update,args)
  db.commit()

下面是另一种方法,它被记录在MySQL官方网站上。

在精神上,它使用了@Trey Stout的答案的相同机制。然而,我发现这一个更漂亮,更具可读性

insert_stmt = (
  "INSERT INTO employees (emp_no, first_name, last_name, hire_date) "
  "VALUES (%s, %s, %s, %s)"
)
data = (2, 'Jane', 'Doe', datetime.date(2012, 3, 23))
cursor.execute(insert_stmt, data)
为了更好地说明变量的需求:

注:注意正在进行的转义

employee_id = 2
first_name = "Jane"
last_name = "Doe"

insert_stmt = (
  "INSERT INTO employees (emp_no, first_name, last_name, hire_date) "
  "VALUES (%s, %s, %s, %s)"
)
data = (employee_id, conn.escape_string(first_name), conn.escape_string(last_name), datetime.date(2012, 3, 23))
cursor.execute(insert_stmt, data)

第一个解决方案运行良好。我想在这里添加一个小细节。确保您尝试替换/更新的变量必须是str类型。我的mysql类型是decimal,但我必须将参数变量设置为str才能执行查询

temp = "100"
myCursor.execute("UPDATE testDB.UPS SET netAmount = %s WHERE auditSysNum = '42452'",(temp,))
myCursor.execute(var)

当var1和var2有类似的字符时,这会起作用吗"或者“.AFAIK您必须在那里使用
%s
,无论是哪种类型。@sheki:Yes@Specto在我看来,始终保持正确和安全的实现方式是有意义的。它创造了正确的习惯和良好的编程文化。而且,没有人知道您的代码将来将如何使用;有人以后可以将其用于其他系统或网站。@BryanHunt您可以在某个地方用参数启用?的用法,但不鼓励使用它,因为它不能告诉您有关哪个参数在哪里。(当然,对于%s也可以这样说,因为同样的原因不鼓励使用它。)这里的更多信息:来自php/pdo,如果
printf
样式
%s
标记,我会非常困惑,我有点害怕我正在编写易受攻击的查询。感谢您消除了这一顾虑!:)当它是单个参数时,请记住保留逗号:
c.execute(“选择*from foo WHERE bar=%s”,(参数1,)
有关游标执行中参数的上下文(以及为什么仍然需要%s),MySQLdb游标的api参考位于Yeah,这是一个奇怪的参考。。。你认为“printf”格式意味着。。。实际上是printf格式,而不仅仅是到处使用%s。我对。。。您设法使python代码不可读!如果给定的绑定变量必须在SQL语句中的多个位置使用,那么字典方法似乎效果更好。使用位置方法时,我们需要传递变量的次数与引用的次数相同,这不是很理想。
employee_id = 2
first_name = "Jane"
last_name = "Doe"

insert_stmt = (
  "INSERT INTO employees (emp_no, first_name, last_name, hire_date) "
  "VALUES (%s, %s, %s, %s)"
)
data = (employee_id, conn.escape_string(first_name), conn.escape_string(last_name), datetime.date(2012, 3, 23))
cursor.execute(insert_stmt, data)
temp = "100"
myCursor.execute("UPDATE testDB.UPS SET netAmount = %s WHERE auditSysNum = '42452'",(temp,))
myCursor.execute(var)