web-dev-qa-db-fra.com

Python MySQLdb TypeError: pas tous les arguments convertis lors du formatage de chaîne

Lors de l'exécution de ce 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")

Je reçois une erreur de:

./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

Je n'ai aucune idée pourquoi. J'essaie de faire des requêtes paramétrées, mais ça n'a été qu'une douleur. Je suis un peu nouveau dans Python, donc c'est probablement un problème évident.

36
Mandatory Programmer

Au lieu de cela:

cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )

Essaye ça:

cur.execute( "SELECT * FROM records WHERE email LIKE %s", [search] )

Voir la documentation MySQLdb . Le raisonnement est que le second paramètre de execute représente une liste des objets à convertir, car vous pourriez avoir un nombre arbitraire d'objets dans une requête paramétrée. Dans ce cas, vous n’en avez qu’un, mais il faut tout de même que ce soit un itératif (un tuple au lieu d’une liste conviendrait également). 

74
kevinsa5

Vous pouvez essayer ce code:

cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", (search,) )

Vous pouvez voir la documentation

16
Mohamed Abd El Raouf

Le mot clé '%' est si dangereux parce qu'il est la principale cause de 'SQL INJECTION ATTACK'. 
Donc vous utilisez simplement ce code.

cursor.execute("select * from table where example=%s", (example,))

ou

t = (example,)
cursor.execute("select * from table where example=%s", t)

si vous voulez essayer d’insérer dans un tableau, essayez ceci.

name = 'ksg'
age = 19
sex = 'male'
t  = (name, age, sex)
cursor.execute("insert into table values(%s,%d,%s)", t)
6
ksg97031
cur.execute( "SELECT * FROM records WHERE email LIKE %s", (search,) )

Je ne sais pas pourquoi, mais cela fonctionne pour moi. plutôt que d'utiliser '%s'.

2
bob90937

J'ai rencontré cette erreur lors de l'exécution de SELECT * FROM table; J'ai tracé l'erreur sur la ligne du curseur.py. 

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))

Étant donné que je saisis des paramètres supplémentaires, je me suis débarrassé de toute la branche "if args ...". Maintenant ça marche. 

0
Adel

La réponse acceptée par @ kevinsa5 est correcte, mais vous pourriez penser: "Je jure que ce code utilisé fonctionne et maintenant il ne fonctionne pas", et vous auriez raison.

Une modification de l'API dans la bibliothèque MySQLdb s'est produite entre 1.2.3 et 1.2.5. Les versions 1.2.3 supportées

cursor.execute("SELECT * FROM foo WHERE bar = %s", 'baz')

mais les versions 1.2.5 nécessitent

cursor.execute("SELECT * FROM foo WHERE bar = %s", ['baz'])

comme le dit l'autre réponse. Je ne trouve pas le changement dans les changelogs, et il est possible que le comportement précédent ait été considéré comme un bogue.

Le référentiel Ubuntu 14.04 a python-mysqldb 1.2.3, mais Ubuntu 16.04 et les versions ultérieures ont python-mysqldb 1.3.7+.

Si vous avez affaire à une base de code héritée qui requiert l'ancien comportement mais que votre plate-forme est une Ubuntu nouvelle génération, installez MySQLdb à partir de PyPI:

$ pip install MySQL-python==1.2.3
0
user4851

Je ne comprends pas les deux premières réponses. Je pense qu'ils doivent être dépendants de la version. Je ne peux pas les reproduire sur MySQLdb 1.2.3, qui est fourni avec Ubuntu 14.04LTS. Essayons les. Tout d'abord, nous vérifions que MySQL n'accepte pas les doubles apostrophes:

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

Nan. Essayons l'exemple que Mandatory a publié à l'aide du constructeur de la requête dans /usr/lib/python2.7/dist-packages/MySQLdb/cursors.py où j'ai ouvert "con" en tant que connexion à ma base de données.

>>> search = "test"
>>> "SELECT * FROM records WHERE email LIKE '%s'" % con.literal(search)
"SELECT * FROM records WHERE email LIKE ''test''"
>>> 

Non, les doubles apostrophes la font échouer. Essayons le premier commentaire de Mike Graham, dans lequel il suggère de laisser les apostrophes citant les% s:

>>> "SELECT * FROM records WHERE email LIKE %s" % con.literal(search)
"SELECT * FROM records WHERE email LIKE 'test'"
>>> 

Oui, cela fonctionnera, mais le deuxième commentaire de Mike et la documentation indiquent que l'argument à exécuter (traité par con.literal) doit être un Tuple (search,) ou une liste [search]. Vous pouvez les essayer, mais vous ne trouverez aucune différence avec le résultat ci-dessus.

La meilleure réponse est celle de ksg97031.

0
Russell Nelson

Selon PEP8, je préfère exécuter SQL de cette façon:

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)

De cette manière, vous reconnaîtrez que le deuxième argument args de la méthode execute doit être une liste d'arguments.

Puisse cela vous aider.

0
stillzhl