176 votes

liste python dans une requête sql comme paramètre

J'ai une liste python, disons l

l = [1,5,8]

Je veux écrire une requête sql pour obtenir les données de tous les éléments de la liste, par exemple

select name from students where id = |IN THE LIST l|

Comment puis-je y parvenir ?

146voto

bobince Points 270740

Jusqu'à présent, les réponses ont consisté à modéliser les valeurs dans une chaîne SQL simple. C'est tout à fait correct pour les entiers, mais si nous voulions le faire pour les chaînes de caractères, nous serions confrontés au problème de l'échappement.

Voici une variante utilisant une requête paramétrée qui fonctionnerait pour les deux :

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

15 votes

','.join(placeholder * len(l)) serait un peu plus court tout en restant lisible, je pense.

7 votes

@Thiefmaster : oui, il faudrait qu'il soit ([placeholder]*len(l)) dans le cas général, car l'espace réservé peut comporter plusieurs caractères.

2 votes

@bobince dans mon cas, j'ai assigné une variable a='john' et b='snow' et je l'ai stockée dans un tuple avec le nom got=['a,b'] et j'ai effectué la même requête. En faisant cela, j'ai obtenu l'erreur suivante : Type Error : not all arguments converted during string formatting. Comment puis-je le résoudre ?

32voto

Blair Conrad Points 56195

Le SQL que vous voulez est

select name from studens where id in (1, 5, 8)

Si vous voulez construire ceci à partir du python vous pouvez utiliser

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'

Le site carte transformera la liste en une liste de chaînes de caractères qui pourront être collées ensemble par des virgules en utilisant la fonction str.join méthode.

Alternativement :

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'

si vous préférez expressions de générateur à la fonction de carte.

UPDATE : S. Lott mentionne dans les commentaires que les liaisons SQLite de Python ne supportent pas les séquences. Dans ce cas, vous pourriez vouloir

select name from studens where id = 1 or id = 5 or id = 8

Généré par

sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))

2 votes

:-( La liaison Python SQLite ne prend pas en charge les séquences.

0 votes

Oh ? Je n'avais pas réalisé. Et encore une fois, je n'avais pas réalisé que nous allions utiliser une solution SQLite.

0 votes

Désolé, je ne suggère pas ou n'implique pas SQLite - je suis juste triste que les liens pour les listes ne fonctionnent pas là.

10voto

gimel Points 30150

string.join les valeurs de la liste séparées par des virgules, et utilisez la fonction opérateur de format pour former une chaîne de requête.

myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))

(Merci, blair-conrad )

5 votes

Comme cette approche n'utilise pas la substitution des paramètres de la base de données, elle vous expose à des attaques par injection SQL. Le site % utilisé ici n'est qu'un simple formatage de chaîne Python.

10voto

jimhark Points 2697

J'aime la réponse de Bobince :

placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)

Mais j'ai remarqué ceci :

placeholders= ', '.join(placeholder for unused in l)

Peut être remplacé par :

placeholders= ', '.join(placeholder*len(l))

Je trouve cela plus direct, bien que moins intelligent et moins général. Voici l doit avoir une longueur (c'est-à-dire qu'il doit se référer à un objet qui définit un __len__ ), ce qui ne devrait pas poser de problème. Mais le placeholder doit également être un caractère unique. Pour prendre en charge un placeholder à plusieurs caractères, utilisez :

placeholders= ', '.join([placeholder]*len(l))

2voto

unmounted Points 10968

Voici un moyen, où cursor est votre objet curseur habituel :

>>> random_ids = [1234,123,54,56,57,58,78,91]
>>> cursor.execute("create table test (id)")
>>> for item in random_ids:
    cursor.execute("insert into test values (%d)" % item)
>>> sublist = [56,57,58]
>>> cursor.execute("select id from test where id in %s" % str(tuple(sublist)))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X