web-dev-qa-db-fra.com

Requêtes MySQL paramétrées

J'ai du mal à utiliser le module MySQLdb pour insérer des informations dans ma base de données. Je dois insérer 6 variables dans le tableau. 

cursor.execute ("""
    INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
    VALUES
        (var1, var2, var3, var4, var5, var6)

""")

Quelqu'un peut-il m'aider avec la syntaxe ici?

65
Specto

Méfiez-vous de l'interpolation de chaîne pour les requêtes SQL, car elle n'échappera pas correctement aux paramètres d'entrée et laissera votre application ouverte aux vulnérabilités d'injection SQL. La différence peut sembler triviale, mais en réalité, elle est énorme .

Incorrect (avec des problèmes de sécurité)

c.execute("SELECT * FROM foo WHERE bar = %s AND baz = %s" % (param1, param2))

Correct (avec échappement)

c.execute("SELECT * FROM foo WHERE bar = %s AND baz = %s", (param1, param2))

Cela ajoute à la confusion que les modificateurs utilisés pour lier les paramètres dans une instruction SQL varient selon les implémentations de l'API de base de données et que la bibliothèque client mysql utilise la syntaxe de style printf au lieu du plus communément accepté '?' marqueur (utilisé par exemple. python-sqlite).

218
Emil H

Vous avez quelques options disponibles. Vous voudrez vous familiariser avec la chaîne iterpolation de python. C’est un terme que vous aurez peut-être plus de succès à rechercher à l’avenir lorsque vous souhaitez connaître des informations de ce type.

Mieux pour les requêtes:

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)

Étant donné que vous avez probablement déjà toutes vos données dans un objet ou un dictionnaire, le second format vous conviendra mieux. De plus, il est nul de devoir compter "% s" dans une chaîne lorsque vous devez revenir et mettre à jour cette méthode dans un an :)

35
Trey Stout

Les documents liés donnent l'exemple suivant:

   cursor.execute ("""
         UPDATE animal SET name = %s
         WHERE name = %s
       """, ("snake", "turtle"))
   print "Number of rows updated: %d" % cursor.rowcount

Il vous suffit donc d’adapter cela à votre propre code - exemple:

cursor.execute ("""
            INSERT INTO Songs (SongName, SongArtist, SongAlbum, SongGenre, SongLength, SongLocation)
            VALUES
                (%s, %s, %s, %s, %s, %s)

        """, (var1, var2, var3, var4, var5, var6))

(Si SongLength est numérique, vous devrez peut-être utiliser% d au lieu de% s).

13
Marcel Guzman

En guise d'alternative à la réponse choisie et avec la même sémantique sûre que celle de Marcel, voici un moyen compact d'utiliser un dictionnaire Python pour spécifier les valeurs. Il a l'avantage d'être facile à modifier lorsque vous ajoutez ou supprimez des colonnes à insérer:

  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 est le dictionnaire contenant les valeurs à insérer. La mise à jour peut se faire de la même manière:

  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()
5
FDS

En réalité, même si votre variable (SongLength) est numérique, vous devrez quand même la formater avec% s pour lier correctement le paramètre. Si vous essayez d'utiliser% d, vous obtiendrez une erreur. Voici un petit extrait de ce lien http://mysql-python.sourceforge.net/MySQLdb.html :

Pour effectuer une requête, vous devez d'abord disposer d'un curseur, puis vous pouvez y exécuter des requêtes:

c=db.cursor()
max_price=5
c.execute("""SELECT spam, eggs, sausage FROM breakfast
          WHERE price < %s""", (max_price,))

Dans cet exemple, max_price = 5 Pourquoi, alors, utiliser% s dans la chaîne? Parce que MySQLdb le convertira en une valeur littérale SQL, qui correspond à la chaîne '5'. Quand ce sera terminé, la requête indiquera en fait "... WHERE price <5".

5
daSong

La première solution fonctionne bien. Je veux ajouter un petit détail ici. Assurez-vous que la variable que vous essayez de remplacer/mettre à jour doit être de type str. Mon type mysql est décimal, mais je devais définir le paramètre variable comme str pour pouvoir exécuter la requête. 

temp = "100"
myCursor.execute("UPDATE testDB.UPS SET netAmount = %s WHERE auditSysNum = '42452'",(temp,))
myCursor.execute(var)
0
Parth Shah

Voici une autre façon de le faire. C'est documenté sur le site officiel de MySQL . https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html

Dans l’esprit, il utilise le même mécanisme que celui de @Trey Stout. Cependant, je trouve celui-ci plus joli et plus lisible.

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)

Et pour mieux illustrer le besoin de variables:

NB: notez l'évasion en cours.

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