Eu tenho uma lista python, digamos, l
l = [1,5,8]
Eu quero escrever uma consulta sql para obter os dados de todos os elementos da lista, digamos
select name from students where id = |IN THE LIST l|
Como eu faço isso?
Eu tenho uma lista python, digamos, l
l = [1,5,8]
Eu quero escrever uma consulta sql para obter os dados de todos os elementos da lista, digamos
select name from students where id = |IN THE LIST l|
Como eu faço isso?
Respostas:
Até agora, as respostas foram modelar os valores em uma sequência SQL simples. Isso é absolutamente bom para números inteiros, mas se quisermos fazer isso por strings, obtemos o problema de escape.
Aqui está uma variante usando uma consulta parametrizada que funcionaria 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))
no caso geral, pois o espaço reservado pode ter vários caracteres.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)
. @bince, você também deve observar em sua solução que o uso ?
é o caminho seguro para evitar a injeção de SQL. Há muitas respostas aqui vulneráveis, basicamente as que concatenam cadeias de caracteres em python.
A maneira mais fácil é transformar a lista em tuple
primeiro lugar
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Não complique, a solução para isso é simples.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
Espero que isso tenha ajudado !!!
l
apenas contiver um elemento, você vai acabar com id IN (1,)
. O que é um erro de sintaxe.
sqlite3
. Em qual biblioteca você testou isso?
O SQL que você deseja é
select name from studens where id in (1, 5, 8)
Se você deseja construir isso a partir do python, você pode usar
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
A função map transformará a lista em uma lista de cadeias que podem ser coladas por vírgulas usando o 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)) + ')'
se você preferir expressões geradoras à função map.
UPDATE: S. Lott menciona nos comentários que as ligações Python SQLite não suportam sequências. Nesse caso, você pode querer
select name from studens where id = 1 or id = 5 or id = 8
Gerado por
sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))
string.join os valores da lista separados por vírgulas e use o operador format para formar uma string de consulta.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Obrigado, Blair-Conrad )
%
está sendo usado aqui é apenas uma formatação simples de string Python.
Eu gosto da resposta 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)
Mas eu notei isso:
placeholders= ', '.join(placeholder for unused in l)
Pode ser substituído por:
placeholders= ', '.join(placeholder*len(l))
Acho isso mais direto, se menos inteligente e menos geral. Aqui l
é necessário ter um comprimento (ou seja, referir-se a um objeto que define um __len__
método), o que não deve ser um problema. Mas o espaço reservado também deve ser um único caractere. Para oferecer suporte a um espaço reservado para vários caracteres, use:
placeholders= ', '.join([placeholder]*len(l))
Solução para resposta @umounted, porque ela quebrou com uma tupla de um elemento, pois (1,) não é 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,)]
Outra solução para sql string:
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)
Isso deve resolver seu problema.
Se você estiver usando o PostgreSQL com a biblioteca Psycopg2, poderá permitir que sua adaptação à tupla faça toda a interpolação de escape e de string para você, por exemplo:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
ou seja, apenas verifique se você está passando o IN
parâmetro como a tuple
. se for um, list
você pode usar a = ANY
sintaxe da matriz :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
observe que esses dois serão transformados no mesmo plano de consulta; portanto, você deve usar o que for mais fácil. por exemplo, se sua lista vem em uma tupla, use a primeira, se eles estão armazenados em uma lista, use a segunda.
uma solução mais simples:
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)
A :var
notação parece mais simples. (Python 3.7)
Isso usa substituição de parâmetro e cuida do caso da 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))
seria um pouco menor, enquanto ainda imho legível