У меня есть список питонов, скажем я
l = [1,5,8]
Я хочу написать sql-запрос, чтобы получить данные для всех элементов списка, скажем
select name from students where id = |IN THE LIST l|
Как мне этого добиться?
У меня есть список питонов, скажем я
l = [1,5,8]
Я хочу написать sql-запрос, чтобы получить данные для всех элементов списка, скажем
select name from students where id = |IN THE LIST l|
Как мне этого добиться?
Ответы:
Ответы до сих пор представляли собой шаблон значений в простой строке SQL. Это абсолютно нормально для целых чисел, но если мы хотим сделать это для строк, мы получим проблему с экранированием.
Вот вариант, использующий параметризованный запрос, который будет работать для обоих:
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))в общем случае, поскольку заполнитель может состоять из нескольких символов.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l) . @bobince, вы также должны отметить в своем решении, что использование ?- это безопасный способ избежать внедрения SQL. Здесь есть множество уязвимых ответов, в основном те, которые объединяют строки в python.
Самый простой способ - поставить список tupleпервым
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Не усложняйте это, решение простое.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
Надеюсь, это помогло !!!
lсодержит только один элемент, и вы получите id IN (1,). Это синтаксическая ошибка.
sqlite3. С какой библиотекой вы это тестировали?
Вам нужен SQL
select name from studens where id in (1, 5, 8)
Если вы хотите построить это из питона, вы можете использовать
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
Функция map преобразует список в список строк, которые можно склеить запятыми с помощью метода str.join .
В качестве альтернативы:
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'
если вы предпочитаете выражения генератора функции карты.
ОБНОВЛЕНИЕ: С. Лотт упоминает в комментариях, что привязки Python SQLite не поддерживают последовательности. В этом случае вы можете захотеть
select name from studens where id = 1 or id = 5 or id = 8
Создан
sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))
строка. соедините значения списка, разделенные запятыми, и используйте оператор формата для формирования строки запроса.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Спасибо, Блэр-Конрад )
%используется простое форматирование строки Python.
Мне нравится ответ Бобинса:
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)
Но я заметил вот что:
placeholders= ', '.join(placeholder for unused in l)
Можно заменить на:
placeholders= ', '.join(placeholder*len(l))
Я считаю это более прямым, хотя и менее умным и менее общим. Здесь lтребуется указать длину (то есть ссылаться на объект, определяющий __len__метод), что не должно быть проблемой. Но заполнитель также должен быть одиночным символом. Для поддержки использования многосимвольных заполнителей:
placeholders= ', '.join([placeholder]*len(l))
Решение для @umounted ответа, потому что это сломалось с одноэлементным кортежем, поскольку (1,) не является допустимым SQL .:
>>> 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,)]
Другое решение для строки 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)
Это должно решить вашу проблему.
Если вы используете PostgreSQL с библиотекой Psycopg2, вы можете позволить его адаптации кортежа делать за вас все экранирование и интерполяцию строк, например:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
т.е. просто убедитесь, что вы передаете INпараметр как tuple. если это, listвы можете использовать = ANYсинтаксис массива :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
обратите внимание, что они оба будут преобразованы в один и тот же план запроса, поэтому вам следует просто использовать то, что проще. например, если ваш список входит в состав кортежа, используйте первое, если они хранятся в списке, используйте второе.
более простое решение:
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)
:varНотация кажется проще. (Python 3.7)
Здесь используется подстановка параметров и учитывается случай списка с одним значением:
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))будет немного короче, но все равно читабельно imho