Список python в запросе sql как параметр

У меня есть список питонов, скажем я

l = [1,5,8]

Я хочу написать sql-запрос, чтобы получить данные для всех элементов списка, скажем

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

Как мне этого добиться?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
136
0
137 723
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

string.join значения списка, разделенные запятыми, и использование оператор формата для формирования строки запроса.

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

(Спасибо, Блэр-Конрад)

Поскольку этот подход не использует подстановку параметров базы данных, он подвергает вас атакам с использованием SQL-инъекций. Используемый здесь % представляет собой простое форматирование строки Python.

Nick Chammas 16.12.2018 23:27

Вам нужен 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)) + ')'

Функция карта преобразует список в список строк, которые можно склеить запятыми с помощью метода 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))

:-( Привязка Python SQLite не поддерживает последовательности.

S.Lott 12.11.2008 15:04

Ой? Я не понимал. Опять же, я не понимал, что мы собираемся использовать решение для привязки SQLite.

Blair Conrad 12.11.2008 15:15

Извините, я не предлагаю и не подразумеваю SQLite - просто грустно, что привязки для списков там не работают.

S.Lott 12.11.2008 18:27
Ответ принят как подходящий

До сих пор в ответах использовались шаблоны значений в простой строке 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)
','.join(placeholder * len(l)) был бы немного короче, но все еще читабельный imho
ThiefMaster 02.05.2013 00:50

@Thiefmaster: да, в общем случае это должен быть ([placeholder]*len(l)), поскольку заполнитель может состоять из нескольких символов.

bobince 02.05.2013 04:28

@bobince в моем случае я назначил переменную a = 'john' и b = 'snow' и сохранил ее в кортеже с именем got = ['a, b'] и выполнил тот же запрос. При этом я получил ошибку, т.е. ошибку типа: не все аргументы преобразованы во время форматирования строки. Как я должен это решить?

sigdelsanjog 09.01.2015 22:55

Почему вы хотите присоединиться «вручную», а не оставлять эту работу dbapi? ключ в том, чтобы использовать кортеж, а не список ...

Alessandro Dentella 11.01.2017 12:24

@AlessandroDentella, sqlite его не поддерживает. пример явно добавляет ? в предложение INSERT, которое аналогично предложению IN.

toto_tico 31.08.2017 12:34

Да, передача кортежа в качестве параметра - это то, что не является стандартной функцией DB-API, и для %-paramstyle это, вероятно, не делает то, что вы думаете - это на самом деле вызывает str в кортеже и вставляет репозиторий Python в Строка запроса. Это работает, когда это кортеж из как минимум двух целых чисел, каждое из которых должно быть слишком маленьким, чтобы получить суффикс L. Он не работает в большинстве других случаев - и, в частности, не работает для строковых литералов, что делает его уязвимостью SQL-инъекций. Не делай этого!

bobince 01.09.2017 22:10

У меня есть список повторяющихся данных, которые должны быть переданы как список заполнителей, но sql выполняется только как установлено

Pawankumar Dubey 31.03.2018 20:44

На основе этого ответа предлагается однострочное решение для Python 3.6cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l). @bobince, вы также должны отметить в своем решении, что использование ? - это безопасный способ избежать SQL-инъекций. Здесь много уязвимых ответов, в основном те, которые объединяют строки в python.

toto_tico 24.05.2018 16:40

@roganjosh, согласен, и на самом деле ошибается: cursor.execute(f"SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})", l). К сожалению, вариантов не так много, если вы хотите избежать SQL-инъекции, я бы разделил одну строку на несколько 2 или 3. В этом случае одна строка удобна в качестве примера того, как использовать Python f-strings. В исходном ответе третья строка будет выглядеть так: query= f'SELECT name FROM students WHERE id IN ({placeholders})'.

toto_tico 06.10.2018 13:30

@bobince Можно ли подробнее рассказать о комментарии, «все из которых должны быть слишком маленькими, чтобы получить суффикс L. Он не работает в большинстве других случаев - и, в частности, не работает для строковых литералов, что делает его уязвимостью для SQL-инъекций» ?

Lei Hao 13.08.2019 09:39

@LeiHao В Python 2 число с суффиксом L, например 98L, является длинным целым числом. Если число слишком велико, чтобы быть коротким целым числом, например 80000000000, то repr() возвращает значение с суффиксом L. Python 3 никогда этого не делает, потому что целочисленный тип полностью обрабатывает его. Python 3.

Bacon Bits 07.02.2020 16:46

что, если мне нужно передать дополнительный параметр вместе со списком l в запросе. query= 'SELECT name FROM students WHERE id IN (%s) and name= %(name)s' % placeholders ??

Rahul Reddy 17.04.2020 01:22

Мне нравится ответ Бобинса:

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)+'"'))

Это не лучшее решение из-за внедрения sql.

Anurag 13.02.2016 11:09

Например, если вам нужен запрос sql:

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

Что о:

my_list = [1, 5, 8]
cur.execute("select name from studens where id in %s" % repr(my_list).replace('[','(').replace(']',')') )

Не усложняйте это, решение простое.

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,). Это синтаксическая ошибка.

renstrm 30.11.2016 12:12

Если это только один элемент, IN - это не тот оператор, который вам нужен. OP явно не делает; t.

allsyed 23.12.2016 07:48

Если l содержит только 1 элемент, убедитесь, что это кортеж, и он БУДЕТ работать. На мой взгляд, это решение более ясное, чем принятое.

Alessandro Dentella 11.01.2017 12:20

Но это все равно не сработает, если кортеж пуст, поэтому перед выполнением запроса должна быть дополнительная проверка.

Никита Конин 17.04.2017 15:22

Некоторые соединители баз данных (например, соединение pyodbc с SQL Server) не поддерживают именованные параметры, поэтому это не всегда сработает.

LexH 24.10.2018 00:30

У меня это не работает с sqlite3. С какой библиотекой вы это тестировали?

Nick Chammas 16.12.2018 23:38

Это лучший пример, поскольку он имеет простое решение для создания строк, а также предотвращает внедрение sql.

DaveRGP 23.04.2019 13:08

Хорошее решение, но @renstrm и Никита-Конин правы, требуя дополнительных проверок, когда в кортеже есть один элемент или нет элементов.

Anish Sana 26.06.2019 20:19

Это правильный ответ. Использую красное смещение и панды, вот оно: pd.read_sql_query(sql='select * from table where id in :ids_tuple', con=..., params = {'ids_tuple':l}); Очень удобно. и вы можете заменять списки идентификаторов в цикле без перекомпиляции запроса.

Alex Fedotov 14.07.2020 00:13

Самый простой способ - сначала перевернуть список на tuple

t = tuple(l)
query = "select name from studens where id IN {}".format(t)

На самом деле это правильный ответ. Я не уверен, почему это было проигнорировано. Сначала вы настраиваете список l, затем используете кортеж, а затем передаете кортеж в запрос. отличная работа.

MEdwin 13.11.2018 13:25

Это настоящий ответ.

James 28.01.2019 12:34

Согласен, это лучший ответ!

Emac 08.04.2019 18:00

Красиво и чисто!

Michel Floyd 29.05.2019 12:51

Как указано в @renstrm, это не сработает, если l содержит только один элемент, вы получите id IN (1,). Это синтаксическая ошибка.

Doubledown 30.05.2019 05:28

если у вас только один элемент, вам не нужно использовать IN. вы можете просто сделать =

Amir Imani 30.07.2019 23:10

@Amirhos Imani, а что, если вы не знаете, сколько элементов у вас есть?

Boris 22.11.2019 16:35

@Boris, если вы не можете гарантировать, что ваш ввод всегда является списком, вы можете сделать что-то похожее на этот лайнер stackoverflow.com/questions/38821586/…, прежде чем передавать аргумент вашему запросу

Amir Imani 26.11.2019 18:17

Это, как и большинство ответов здесь, кроме принятого, уязвимо для SQL-инъекции и не должно использоваться.

Bacon Bits 30.12.2019 00:22

@BaconBits Справедливое предупреждение, но для некоторых приложений, где SQL-инъекция не является проблемой (например, анализ базы данных, в которой я единственный пользователь), это подойдет.

irene 07.02.2020 11:13

да, это не работает для одного элемента, просто понял

Sibish 17.04.2020 02:50

При этом используется подстановка параметров и учитывается случай списка с одним значением:

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),))
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)

Это должно решить вашу проблему.

более простое решение:

lst = [1,2,3,a,b,c]

query = f"""SELECT * FROM table WHERE IN {str(lst)[1:-1}"""

Если вы используете 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)])

обратите внимание, что они оба будут преобразованы в один и тот же план запроса, поэтому вам следует просто использовать то, что проще. например если ваш список представлен в виде кортежа, используйте первое, если они хранятся в списке, используйте второе.

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)

Это будет работать, если количество значений в списке равно 1 или больше 1

t = str(tuple(l))
if t[-2] == ',':
   t= t.replace(t[-2],"")
query = "select name from studens where id IN {}".format(t)

Просто используйте встроенную операцию if с функцией кортежа:

query = "Select * from hr_employee WHERE id in " % tuple(employee_ids) if len(employee_ids) != 1 else "("+ str(employee_ids[0]) + ")"

Моя проблема заключалась в параметризованных запросах. Введенный параметр списка всегда заканчивал тем, что его значения были заключены в кавычки в результирующих предложениях SQL IN, что чертовски сбивало с толку. Идея tuple() сработала. Это работает, потому что DJango переводит это в строковый формат, подходящий для предложения SQL IN(). Именно это меня не поразило, когда в нескольких ответах предлагалось использовать tuple.

theruss 20.01.2021 02:16

Чтобы запустить выбор, где поле находится в списке строк (вместо int), согласно этому вопросу использует repr(tuple(map(str, l))). Полный пример:

l = ['a','b','c']
sql = f'''

select name 
from students 
where id in {repr(tuple(map(str, l)))}
'''
print(sql)

Возврат: select name from students where id in ('a', 'b', 'c')

Для списка дат в Oracle это сработало

dates_str = ','.join([f'DATE {repr(s)}' for s in ['2020-11-24', '2020-12-28']])
dates_str = f'({dates_str})'

sql_cmd = f'''
select *
from students 
where 
and date in {dates_str}
'''

Возврат: select * from students where and date in (DATE '2020-11-24',DATE '2020-12-28')

Другие вопросы по теме