我有下面这段 Python 代码:
cursor.execute("INSERT INTO table VALUES var1, var2, var3,")
其中var1
是整数,var2
和var3
是字符串。
我该如何在Python代码中将这些变量名写入而不让它们成为查询文本的一部分?
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))
需要注意的是,参数被作为一个元组 (a, b, c)
传递。如果你只传递一个参数,该元组需要以逗号结尾,如:(a,)
。
数据库API会对变量进行适当的转义和引用。请小心不要使用字符串格式化操作符(%
),因为:
Python的不同DB-API实现允许使用不同的占位符,因此您需要找出您正在使用哪个占位符——例如,在使用MySQLdb时可能为:
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))
或者(例如使用Python标准库中的sqlite3):
cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3))
或者其他方式(在 VALUES
后,你可以使用 (:1, :2, :3)
或 "命名风格" (:fee, :fie, :fo)
或 (%(fee)s, %(fie)s, %(fo)s)
,在第二个参数中传递字典而不是映射给 execute
)。查看您正在使用的 DB API 模块中的paramstyle
字符串常量,并查看 http://www.python.org/dev/peps/pep-0249/ 上的 paramstyle,以了解所有参数传递样式!%
的%s
),它容易受到攻击。......要注意,不要使用Python的字符串操作来组装查询,因为它们容易受到SQL注入攻击的影响。例如,攻击者可以简单地关闭单引号并注入OR TRUE以选择所有行:
# Never do this -- insecure!
symbol = input()
sql = "SELECT * FROM stocks WHERE symbol = '%s'" % symbol
print(sql)
cur.execute(sql)
如果您需要更多示例:
# Multiple values single statement/execution
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO'))
print c.fetchall()
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO'))
print c.fetchall()
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice.
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO')
print c.fetchall()
# Insert a single item
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00))
http://www.amk.ca/python/writing/DB-API.html
在将变量的值附加到语句中时要小心:
想象一下一个用户给自己取名为';DROP TABLE Users;'
-- 这就是为什么在使用cursor.execute
时需要使用SQL转义,而Python会在你以适当的方式使用它时提供这种转义。示例在URL中:
cursor.execute("insert into Attendees values (?, ?, ?)", (name, seminar, paid))
对于缺乏经验的Python用户来说,提供单个值的语法可能会让人感到困惑。
给定查询
INSERT INTO mytable (fruit) VALUES (%s)
通常情况下,传递给cursor.execute
的值必须被包装在一个有序序列中,例如元组或列表,即使该值本身是单例,因此我们必须提供一个单元素元组,就像这样:(value,)
。
cursor.execute("""INSERT INTO mytable (fruit) VALUES (%s)""", ('apple',))
cursor.execute("""INSERT INTO mytable (fruit) VALUES (%s)""", ('apple'))
如果出现以下情况,将会导致错误,具体错误类型取决于DB-API连接器:
TypeError: 在字符串格式化期间未转换所有参数
sqlite3.ProgrammingError: 提供的绑定数量不正确。当前语句使用1个,但提供了5个
mysql.connector.errors.ProgrammingError: 1064 (42000): SQL语法存在错误;
* pymysql连接器可以处理单个字符串参数而不出错。但是,最好将字符串包装在元组中,即使它只是一个单独的字符串,因为
将您的数据加载为自动归一化表,我建议使用这个库来推断模式、类型化数据,并支持模式演化 https://pypi.org/project/dlt/
您甚至可以使用这个库在结构化数据之后执行 upsert 操作,下面是一个示例,其中我们使用 JSON 中的 ID 来更新生成的目标 SQL 表
data = [{'id': 1, 'name': 'John'}]
# open connection
pipe = dlt.pipeline(destination='postgres',
dataset_name='raw_data')
# Upsert/merge: Update old records, insert new
# Capture the outcome in load info
load_info = pipe.run(data,
write_disposition="merge",
primary_key="id",
table_name="users")
%
而不是,
在字符串和变量之间..由于各种原因,我无法撤销我的投票..我个人希望在描述中提到像不安全/攻击等词语,其中你说不要使用%
.. - Kashyap