Python MySQLdb TypeError: не все аргументы, преобразованные во время форматирования строки
После запуска этого script:
#! /usr/bin/env python
import MySQLdb as mdb
import sys
class Test:
def check(self, search):
try:
con = mdb.connect('localhost', 'root', 'password', 'recordsdb');
cur = con.cursor()
cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )
ver = cur.fetchone()
print "Output : %s " % ver
except mdb.Error, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
finally:
if con:
con.close()
test = Test()
test.check("test")
Я получаю сообщение об ошибке:
./lookup
Traceback (most recent call last):
File "./lookup", line 27, in <module>
test.check("test")
File "./lookup", line 11, in creep
cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )
File "/usr/local/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 187, in execute
query = query % tuple([db.literal(item) for item in args])
TypeError: not all arguments converted during string formatting
У меня нет идеи, почему. Я пытаюсь сделать параметризованные запросы, но это была не что иное, как боль. Я немного новичок в Python, поэтому, вероятно, это очевидная проблема.
Ответы
Ответ 1
Вместо этого:
cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )
Попробуй это:
cur.execute( "SELECT * FROM records WHERE email LIKE %s", [search] )
См. Документацию по MySQLdb. Смысл заключается в том, что execute
второй параметр представляет собой список объектов, должны быть преобразованы, потому что вы можете иметь произвольное число объектов в параметризованных запросов. В этом случае у вас есть только один, но он все равно должен быть итерируемым (кортеж вместо списка тоже будет прекрасен).
Ответ 2
Вы можете попробовать этот код:
cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", (search,) )
Вы можете увидеть документацию
Ответ 3
Ключевое слово '%' настолько опасно, что является основной причиной "SQL INJECTION ATTACK".
Таким образом, вы просто используете этот код.
cursor.execute("select * from table where example=%s", (example,))
или
t = (example,)
cursor.execute("select * from table where example=%s", t)
если вы хотите попробовать вставить в таблицу, попробуйте это.
name = 'ksg'
age = 19
sex = 'male'
t = (name, age, sex)
cursor.execute("insert into table values(%s,%d,%s)", t)
Ответ 4
cur.execute( "SELECT * FROM records WHERE email LIKE %s", (search,) )
Я не понимаю, но это работает для меня. вместо использования '%s'
.
Ответ 5
Я не понимаю первые два ответа. Я думаю, что они должны быть зависимыми от версии. Я не могу воспроизвести их на MySQLdb 1.2.3, который поставляется с Ubuntu 14.04LTS. Попробуй их. Во-первых, мы проверяем, что MySQL не принимает двойные апострофы:
mysql> select * from methods limit 1;
+----------+--------------------+------------+
| MethodID | MethodDescription | MethodLink |
+----------+--------------------+------------+
| 32 | Autonomous Sensing | NULL |
+----------+--------------------+------------+
1 row in set (0.01 sec)
mysql> select * from methods where MethodID = ''32'';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '9999'' ' at line 1
Неа. Попробуйте пример, который обязательный отправил с помощью конструктора запросов внутри /usr/lib/python2.7/dist-packages/MySQLdb/cursors.py
, где я открыл "con" в качестве подключения к моей базе данных.
>>> search = "test"
>>> "SELECT * FROM records WHERE email LIKE '%s'" % con.literal(search)
"SELECT * FROM records WHERE email LIKE ''test''"
>>>
Нет, двойные апострофы заставляют его терпеть неудачу. Давайте попробуем первый комментарий Майка Грэма, где он предлагает оставить апострофы, цитируя% s:
>>> "SELECT * FROM records WHERE email LIKE %s" % con.literal(search)
"SELECT * FROM records WHERE email LIKE 'test'"
>>>
Да, это сработает, но второй комментарий Майка и документация говорят, что аргумент для выполнения (обрабатываемый con.literal) должен быть кортежем (search,)
или списком [search]
. Вы можете попробовать их, но вы не найдете отличий от вышеприведенного вывода.
Лучший ответ - ksg97031's.
Ответ 6
В соответствии с PEP8 я предпочитаю выполнять SQL таким образом:
cur = con.cursor()
# There is no need to add single-quota to the surrounding of `%s`,
# because the MySQLdb precompile the sql according to the scheme type
# of each argument in the arguments list.
sql = "SELECT * FROM records WHERE email LIKE %s;"
args = [search, ]
cur.execute(sql, args)
Таким образом, вы поймете, что второй аргумент args
метода execute
должен быть списком аргументов.
Пусть это поможет вам.
Ответ 7
Принятый ответ by @kevinsa5 правильный, но вы можете подумать: "Я клянусь, что этот код работал, а теперь это не так", и вы были бы правы.
В библиотеке MySQLdb между 1.2.3 и 1.2.5 произошло изменение API. Поддерживаемые версии 1.2.3
cursor.execute("SELECT * FROM foo WHERE bar = %s", 'baz')
но версии 1.2.5 требуют
cursor.execute("SELECT * FROM foo WHERE bar = %s", ['baz'])
как утверждают другие ответы. Я не могу найти изменения в списках изменений, и, возможно, более раннее поведение считалось ошибкой.
Репозиторий Ubuntu 14.04 имеет python-mysqldb 1.2.3, но Ubuntu 16.04 и более поздние версии имеют python-mysqldb 1.3. 7+.
Если вы имеете дело с устаревшей базой кода, которая требует старого поведения, но ваша платформа является новым Ubuntu, вместо этого установите MySQLdb из PyPI:
$ pip install MySQL-python==1.2.3
Ответ 8
Я столкнулся с этой ошибкой при выполнении SELECT * FROM table;
Я проследил ошибку до курсора строки 195.
if args is not None:
if isinstance(args, dict):
nargs = {}
for key, item in args.items():
if isinstance(key, unicode):
key = key.encode(db.encoding)
nargs[key] = db.literal(item)
args = nargs
else:
args = tuple(map(db.literal, args))
try:
query = query % args
except TypeError as m:
raise ProgrammingError(str(m))
Учитывая, что я ввожу какие-либо дополнительные параметры, я избавился от всей ветки "if args...". Теперь это работает.