MySQL 参数化查询
- 2024-12-03 08:44:00
- admin 原创
- 162
问题描述:
我很难使用 MySQLdb 模块将信息插入数据库。我需要将 6 个变量插入表中。
cursor.execute ("""
INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
VALUES
(var1, var2, var3, var4, var5, var6)
""")
有人能帮我解释一下这里的语法吗?
解决方案 1:
谨慎使用字符串插值进行 SQL 查询,因为它无法正确转义输入参数,并使您的应用程序容易受到 SQL 注入漏洞的攻击。这种差异可能看起来微不足道,但实际上却很大。
不正确(存在安全问题)
c.execute("SELECT * FROM foo WHERE bar = %s AND baz = %s" % (param1, param2))
正确(带转义)
c.execute("SELECT * FROM foo WHERE bar = %s AND baz = %s", (param1, param2))
这增加了混淆,因为用于绑定 SQL 语句中的参数的修饰符在不同的 DB API 实现之间有所不同,并且 mysql 客户端库使用printf
样式语法而不是更常用的“?”标记(例如使用python-sqlite
)。
解决方案 2:
您有几个可用的选项。您需要熟悉 python 的字符串迭代。当您将来想要了解这类内容时,您可能会更成功地搜索这个术语。
更适合查询:
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”的出现次数也很糟糕 :)
解决方案 3:
链接的文档给出了以下示例:
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)。
解决方案 4:
实际上,即使变量 (SongLength) 是数字,您仍必须使用 %s 格式化它才能正确绑定参数。如果您尝试使用 %d,则会出错。以下是此链接http://mysql-python.sourceforge.net/MySQLdb.html的一小段摘录:
要执行查询,首先需要一个游标,然后就可以在其上执行查询:
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 < 5”。
解决方案 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()
解决方案 6:
第一个解决方案效果很好。我想在这里添加一个小细节。确保您尝试替换/更新的变量必须是 str 类型。我的 mysql 类型是十进制,但我必须将参数变量设为 str 才能执行查询。
temp = "100"
myCursor.execute("UPDATE testDB.UPS SET netAmount = %s WHERE auditSysNum = '42452'",(temp,))
myCursor.execute(var)
解决方案 7:
这是另一种方法。它记录在 MySQL 官方网站上。https
://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html
从本质上讲,它使用了与@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)