Параметризованные запросы MySQL
-
13-09-2019 - |
Вопрос
Мне трудно использовать модуль MySQLdb для вставки информации в мою базу данных.Мне нужно вставить 6 переменных в таблицу.
cursor.execute ("""
INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
VALUES
(var1, var2, var3, var4, var5, var6)
""")
Кто-нибудь может помочь мне с синтаксисом здесь?
Решение
Остерегайтесь использования интерполяции строк для 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
).
Другие советы
У вас есть несколько доступных вариантов.Вам захочется освоиться с итерацией строк в 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" в строке, когда вам нужно вернуться и обновить этот метод через год :)
Связанные документы приводят следующий пример:
cursor.execute ("""
UPDATE animal SET name = %s
WHERE name = %s
""", ("snake", "turtle"))
print "Number of rows updated: %d" % cursor.rowcount
Так что вам просто нужно адаптировать это к вашему собственному коду - example:
cursor.execute ("""
INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
VALUES
(%s, %s, %s, %s, %s, %s)
""", (var1, var2, var3, var4, var5, var6))
(Если длина песни числовая, возможно, вам придется использовать %d вместо %s).
На самом деле, даже если ваша переменная (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'.Когда это будет завершено, запрос фактически скажет: "...ГДЕ цена < 5".
В качестве альтернативы выбранному ответу и с той же безопасной семантикой, что и у Марселя, вот компактный способ использования словаря 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_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.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)
Первое решение работает хорошо.Я хочу добавить сюда одну маленькую деталь.Убедитесь, что переменная, которую вы пытаетесь заменить / обновить, должна иметь тип str.Мой тип mysql - десятичный, но мне пришлось сделать переменную параметра как str, чтобы иметь возможность выполнить запрос.
temp = "100"
myCursor.execute("UPDATE testDB.UPS SET netAmount = %s WHERE auditSysNum = '42452'",(temp,))
myCursor.execute(var)