Передача параметра в DB .execute для списка WHERE IN ... INT - PullRequest
10 голосов
/ 12 февраля 2010

С помощью спецификации API БД Python вы можете передать аргумент параметров в метод execute (). Часть моего утверждения - это предложение WHERE IN, и я использовал кортеж для заполнения IN. Например:

params = ((3, 2, 1), )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)

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

ProgrammingError: ОШИБКА: синтаксическая ошибка в или около ")"
ЛИНИЯ 13: ГДЕ ИД (3,)

Как заставить кортеж правильно работать с предложением?

Ответы [ 4 ]

12 голосов
/ 12 февраля 2010

Редактировать: Пожалуйста, как @rspeer упоминает в комментарии, примите меры предосторожности, чтобы защитить себя от атаки SQL-инъекцией.

Тестирование с pg8000 (интерфейс Pure-Python, совместимый с DB-API 2.0, с ядром базы данных PostgreSQL):

Это рекомендуемый способ передачи нескольких параметров в предложение "IN".

params = [3,2,1]
stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in params)
cursor.execute(stmt, params)

Другое редактирование (полностью протестированный и рабочий пример):

>>> from pg8000 import DBAPI
>>> conn = DBAPI.connect(user="a", database="d", host="localhost", password="p")
>>> c = conn.cursor()
>>> prms = [1,2,3]
>>> stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in prms)
>>> c.execute(stmt,prms)
>>> c.fetchall()
((1, u'myitem1'), (2, u'myitem2'), (3, u'myitem3'))
1 голос
/ 07 апреля 2017

Принятый ответ рискует SQL-инъекцией; Вы никогда не должны передавать пользовательский ввод непосредственно в базу данных. Вместо этого сгенерируйте запрос с правильным количеством заполнителей, а затем разрешите экранированию pg8000:

params = [3,2,1]
# SELECT * from table where id in (%s,%s,%s)
stmt = 'SELECT * FROM table WHERE id IN ({})'.format(','.join(['%s']*len(params)))
cursor.execute(stmt, tuple(params))
1 голос
/ 17 августа 2016

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

DB-API Python, по-видимому, не дает вам возможности передавать кортежи как безопасно замененные параметры. Принятым ответом Берни является использование оператора замещения Python %, что небезопасно.

Однако вам может не потребоваться передавать кортежи в качестве параметров, особенно если нужный кортеж является результатом другого запроса SQL (как вы указали Дэниелу). Вместо этого вы можете использовать подзапросы SQL.

Если набор идентификаторов, который вы хотите в предложении IN, является результатом SELECT id FROM other_table WHERE use=true, например:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE use=true)"
db.execute(stmt)

И это тоже можно параметризировать (безопасный способ). Если идентификаторы, которые вы хотите выбрать, это идентификаторы с указанным parent_id:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE parent_id=%s)"
params = (parent_id,)
db.execute(stmt, params)
1 голос
/ 12 февраля 2010

Ошибка идет через запятую после 3. Просто оставьте ее для единичных значений, и все готово.

params = ((3), ... )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...