





string.join значения списка, разделенные запятыми, и использование оператор формата для формирования строки запроса.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Спасибо, Блэр-Конрад)
Вам нужен 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 не поддерживает последовательности.
Ой? Я не понимал. Опять же, я не понимал, что мы собираемся использовать решение для привязки SQLite.
Извините, я не предлагаю и не подразумеваю SQLite - просто грустно, что привязки для списков там не работают.
До сих пор в ответах использовались шаблоны значений в простой строке 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: да, в общем случае это должен быть ([placeholder]*len(l)), поскольку заполнитель может состоять из нескольких символов.
@bobince в моем случае я назначил переменную a = 'john' и b = 'snow' и сохранил ее в кортеже с именем got = ['a, b'] и выполнил тот же запрос. При этом я получил ошибку, т.е. ошибку типа: не все аргументы преобразованы во время форматирования строки. Как я должен это решить?
Почему вы хотите присоединиться «вручную», а не оставлять эту работу dbapi? ключ в том, чтобы использовать кортеж, а не список ...
@AlessandroDentella, sqlite его не поддерживает. пример явно добавляет ? в предложение INSERT, которое аналогично предложению IN.
Да, передача кортежа в качестве параметра - это то, что не является стандартной функцией DB-API, и для %-paramstyle это, вероятно, не делает то, что вы думаете - это на самом деле вызывает str в кортеже и вставляет репозиторий Python в Строка запроса. Это работает, когда это кортеж из как минимум двух целых чисел, каждое из которых должно быть слишком маленьким, чтобы получить суффикс L. Он не работает в большинстве других случаев - и, в частности, не работает для строковых литералов, что делает его уязвимостью SQL-инъекций. Не делай этого!
У меня есть список повторяющихся данных, которые должны быть переданы как список заполнителей, но sql выполняется только как установлено
На основе этого ответа предлагается однострочное решение для Python 3.6cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l). @bobince, вы также должны отметить в своем решении, что использование ? - это безопасный способ избежать SQL-инъекций. Здесь много уязвимых ответов, в основном те, которые объединяют строки в python.
@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})'.
@bobince Можно ли подробнее рассказать о комментарии, «все из которых должны быть слишком маленькими, чтобы получить суффикс L. Он не работает в большинстве других случаев - и, в частности, не работает для строковых литералов, что делает его уязвимостью для SQL-инъекций» ?
@LeiHao В Python 2 число с суффиксом L, например 98L, является длинным целым числом. Если число слишком велико, чтобы быть коротким целым числом, например 80000000000, то repr() возвращает значение с суффиксом L. Python 3 никогда этого не делает, потому что целочисленный тип полностью обрабатывает его. Python 3.
что, если мне нужно передать дополнительный параметр вместе со списком l в запросе. query= 'SELECT name FROM students WHERE id IN (%s) and name= %(name)s' % placeholders ??
Мне нравится ответ Бобинса:
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.
Например, если вам нужен запрос 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,). Это синтаксическая ошибка.
Если это только один элемент, IN - это не тот оператор, который вам нужен. OP явно не делает; t.
Если l содержит только 1 элемент, убедитесь, что это кортеж, и он БУДЕТ работать. На мой взгляд, это решение более ясное, чем принятое.
Но это все равно не сработает, если кортеж пуст, поэтому перед выполнением запроса должна быть дополнительная проверка.
Некоторые соединители баз данных (например, соединение pyodbc с SQL Server) не поддерживают именованные параметры, поэтому это не всегда сработает.
У меня это не работает с sqlite3. С какой библиотекой вы это тестировали?
Это лучший пример, поскольку он имеет простое решение для создания строк, а также предотвращает внедрение sql.
Хорошее решение, но @renstrm и Никита-Конин правы, требуя дополнительных проверок, когда в кортеже есть один элемент или нет элементов.
Это правильный ответ. Использую красное смещение и панды, вот оно: pd.read_sql_query(sql='select * from table where id in :ids_tuple', con=..., params = {'ids_tuple':l}); Очень удобно. и вы можете заменять списки идентификаторов в цикле без перекомпиляции запроса.
Самый простой способ - сначала перевернуть список на tuple
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
На самом деле это правильный ответ. Я не уверен, почему это было проигнорировано. Сначала вы настраиваете список l, затем используете кортеж, а затем передаете кортеж в запрос. отличная работа.
Это настоящий ответ.
Согласен, это лучший ответ!
Красиво и чисто!
Как указано в @renstrm, это не сработает, если l содержит только один элемент, вы получите id IN (1,). Это синтаксическая ошибка.
если у вас только один элемент, вам не нужно использовать IN. вы можете просто сделать =
@Amirhos Imani, а что, если вы не знаете, сколько элементов у вас есть?
@Boris, если вы не можете гарантировать, что ваш ввод всегда является списком, вы можете сделать что-то похожее на этот лайнер stackoverflow.com/questions/38821586/…, прежде чем передавать аргумент вашему запросу
Это, как и большинство ответов здесь, кроме принятого, уязвимо для SQL-инъекции и не должно использоваться.
@BaconBits Справедливое предупреждение, но для некоторых приложений, где SQL-инъекция не является проблемой (например, анализ базы данных, в которой я единственный пользователь), это подойдет.
да, это не работает для одного элемента, просто понял
При этом используется подстановка параметров и учитывается случай списка с одним значением:
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.
Чтобы запустить выбор, где поле находится в списке строк (вместо 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')
Поскольку этот подход не использует подстановку параметров базы данных, он подвергает вас атакам с использованием SQL-инъекций. Используемый здесь
%представляет собой простое форматирование строки Python.