Tengo una lista de python, digamos l
l = [1,5,8]
Quiero escribir una consulta SQL para obtener los datos de todos los elementos de la lista, digamos
select name from students where id = |IN THE LIST l|
¿Cómo logro esto?
Tengo una lista de python, digamos l
l = [1,5,8]
Quiero escribir una consulta SQL para obtener los datos de todos los elementos de la lista, digamos
select name from students where id = |IN THE LIST l|
¿Cómo logro esto?
Respuestas:
Hasta ahora, las respuestas han estado creando los valores en una cadena SQL simple. Eso está absolutamente bien para los enteros, pero si quisiéramos hacerlo por cadenas obtenemos el problema de escape.
Aquí hay una variante que usa una consulta parametrizada que funcionaría para ambos:
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))en el caso general ya que el marcador de posición puede tener varios caracteres.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l) . @bobince, también debe comentar en su solución que usar ?es la forma segura de evitar la inyección de SQL. Aquí hay muchas respuestas que son vulnerables, básicamente cualquiera que concatene cadenas en python.
La forma más fácil es convertir tupleprimero la lista
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
No lo complique, la solución para esto es simple.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
Espero que esto haya ayudado !!!
lsolo contiene un elemento, terminarás con id IN (1,). Que es un error de sintaxis.
sqlite3. ¿Contra qué biblioteca probaste esto?
El SQL que quieres es
select name from studens where id in (1, 5, 8)
Si quieres construir esto desde la pitón, puedes usar
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
La función de mapa transformará la lista en una lista de cadenas que se pueden unir mediante comas utilizando el método str.join .
Alternativamente:
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'
si prefiere expresiones generadoras a la función de mapa.
ACTUALIZACIÓN: S. Lott menciona en los comentarios que los enlaces Python SQLite no admiten secuencias. En ese caso, es posible que desee
select name from studens where id = 1 or id = 5 or id = 8
Generado por
sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))
string. únete a los valores de la lista separados por comas y usa el operador de formato para formar una cadena de consulta.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Gracias, blair-conrad )
%uso aquí es simplemente formato de cadena Python.
Me gusta la respuesta 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)
Pero me di cuenta de esto:
placeholders= ', '.join(placeholder for unused in l)
Se puede reemplazar con:
placeholders= ', '.join(placeholder*len(l))
Encuentro esto más directo si es menos inteligente y menos general. Aquí lse requiere tener una longitud (es decir, referirse a un objeto que define un __len__método), lo que no debería ser un problema. Pero el marcador de posición también debe ser un solo personaje. Para admitir un uso de marcador de posición de varios caracteres:
placeholders= ', '.join([placeholder]*len(l))
Solución para la respuesta @umounted, porque eso rompió con una tupla de un elemento, ya que (1,) no es SQL válido:
>>> 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,)]
Otra solución para la cadena 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)
Esto debería solucionar tu problema.
Si está utilizando PostgreSQL con la biblioteca Psycopg2, puede dejar que su adaptación de tupla haga toda la interpolación de escape y cadena por usted, por ejemplo:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
es decir, solo asegúrese de pasar el INparámetro como a tuple. si es un listpuede usar la = ANYsintaxis de matriz :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
tenga en cuenta que ambos se convertirán en el mismo plan de consulta, por lo que debe usar el que sea más fácil. por ejemplo, si su lista viene en una tupla, use la primera, si están almacenadas en una lista, use la segunda.
Una solución más 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 :varnotación parece más simple. (Python 3.7)
Esto utiliza la sustitución de parámetros y se ocupa del caso de la lista de valores únicos:
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))sería un poco más corto mientras aún legible en mi humilde opinión