J'ai une liste de python, dis 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, disons
select name from students where id = |IN THE LIST l|
Comment faire cela?
J'ai une liste de python, dis 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, disons
select name from students where id = |IN THE LIST l|
Comment faire cela?
Réponses:
Jusqu'à présent, les réponses ont été des modèles de 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, nous obtenons le problème d'é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)
([placeholder]*len(l))
dans le cas général car l'espace réservé peut être composé de plusieurs caractères.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)
. @bobince, vous devriez également remarquer dans votre solution que l'utilisation ?
est le moyen le plus sûr d'éviter l'injection SQL. Il y a beaucoup de réponses ici qui sont vulnérables, essentiellement celles qui concaténent des chaînes en python.
Le moyen le plus simple est de transformer la liste en tuple
premier
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Ne le compliquez pas, la solution est simple.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
J'espère que cela a aidé !!!
l
ne contient qu'un seul élément, vous vous retrouverez avec id IN (1,)
. Ce qui est une erreur de syntaxe.
sqlite3
. Avec quelle bibliothèque avez-vous testé cela?
Le SQL que vous voulez est
select name from studens where id in (1, 5, 8)
Si vous voulez construire cela à partir du python, vous pouvez utiliser
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
La fonction map transformera la liste en une liste de chaînes qui peuvent être collées ensemble par des virgules à l'aide de la méthode str.join .
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 les expressions génératrices à la fonction map.
MISE À JOUR: S. Lott mentionne dans les commentaires que les liaisons Python SQLite ne prennent pas en charge les séquences. Dans ce cas, vous voudrez peut-être
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))
string.join les valeurs de la liste séparées par des virgules et utilisez l' opérateur 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 )
%
formatage utilisé ici est simplement un formatage de chaîne Python.
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 mais moins intelligent et moins général. Ici, il l
est nécessaire d'avoir une longueur (c'est-à-dire faire référence à un objet qui définit une __len__
méthode), ce qui ne devrait pas poser de problème. Mais l'espace réservé doit également être un caractère unique. Pour prendre en charge une utilisation d'espace réservé à plusieurs caractères:
placeholders= ', '.join([placeholder]*len(l))
Solution pour la réponse @umounted, car cela a rompu avec un tuple à un élément, puisque (1,) n'est pas un SQL valide .:
>>> 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)).replace(',)',')'))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]
Autre solution pour la chaîne SQL:
cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))
placeholders= ', '.join("'{"+str(i)+"}'" for i in range(len(l)))
query="select name from students where id (%s)"%placeholders
query=query.format(*l)
cursor.execute(query)
Cela devrait résoudre votre problème.
Si vous utilisez PostgreSQL avec la bibliothèque Psycopg2, vous pouvez laisser son adaptation de tuple faire tout l'échappement et l'interpolation de chaîne pour vous, par exemple:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
c'est-à-dire assurez-vous simplement que vous passez le IN
paramètre en tant que tuple
. si c'est un, list
vous pouvez utiliser la = ANY
syntaxe du tableau :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
notez que ces deux éléments seront transformés en le même plan de requête, vous devez donc simplement utiliser celui qui est le plus facile. Par exemple, si votre liste vient dans un tuple, utilisez la première, si elle est stockée dans une liste, utilisez la seconde.
une solution plus simple:
lst = [1,2,3,a,b,c]
query = f"""SELECT * FROM table WHERE IN {str(lst)[1:-1}"""
l = [1] # or [1,2,3]
query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)
La :var
notation semble plus simple. (Python 3.7)
Cela utilise la substitution de paramètres et prend en charge le cas de liste à valeur unique:
l = [1,5,8]
get_operator = lambda x: '=' if len(x) == 1 else 'IN'
get_value = lambda x: int(x[0]) if len(x) == 1 else x
query = 'SELECT * FROM table where id ' + get_operator(l) + ' %s'
cursor.execute(query, (get_value(l),))
','.join(placeholder * len(l))
serait un peu plus court tout en restant lisible à mon humble avis