У мене є список пітонів, скажімо, л
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)
Якщо ви хочете побудувати це з python, який ви могли б використовувати
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))
string.поєднайтеся зі списком, розділеними комами, і використовуйте оператор формату для формування рядка запиту.
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))
Рішення для @umount відповіді, оскільки це порушилось з одноелементним кортежем, оскільки (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 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)
Це повинно вирішити вашу проблему.
Якщо ви використовуєте PostgreSQL з бібліотекою Psycopg2, ви можете дозволити його адаптації кортежу виконати для вас усю протікаючу та рядкову інтерполяцію, наприклад:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
тобто переконайтеся, що ви передаєте IN
параметр як tuple
. якщо це a, 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
Нотація здається простіше. (Пітон 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))
буде трохи коротше, поки ще читається імхо