Передача параметра в DB.execute для WHERE IN... INT list
В спецификации API Python DB вы можете передать аргумент параметров методу execute(). Часть моего утверждения - это предложение WHERE IN, и я использовал кортеж для заполнения IN. Например:
params = ((3, 2, 1), )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)
Но когда я сталкиваюсь с ситуацией, когда кортеж параметра является только кортежем из 1 элемента, выполнение не выполняется.
ProgrammingError: ERROR: ошибка синтаксиса в точке или рядом ")"
LINE 13: WHERE id IN (3,)
Как я могу заставить кортеж работать с предложением правильно?
Ответы
Ответ 1
Изменить: Пожалуйста, как @rspeer упоминает в комментарии, предпринимайте меры предосторожности, чтобы защитить себя от атаки SQL-инъекции.
Тестирование с помощью pg8000 (совместимый с DB-API 2.0 интерфейс Pure-Python для механизма базы данных 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'))
Ответ 2
Ошибка возникает из запятой после 3. Просто оставьте ее для одиночных значений и вы установите.
params = ((3), ... )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)
Ответ 3
Это, возможно, не ответ на вопрос, который вы задали, но я думаю, что он может решить вашу проблему.
Python DB-API, похоже, не дает вам возможности передавать кортежи в качестве безопасно замененных параметров. В принятом ответе от bernie используется оператор 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)
Ответ 4
Принятый ответ угрожает 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))
Ответ 5
Решение с помощью f-строки.
params = [...]
stmt = f"SELECT * FROM table WHERE id IN ({','.join(['%s']*len(params ),)})"
db.execute(stmt, params)
Если есть другой параметр-заполнитель, он будет таким
age = 18
params = [...]
stmt = f"SELECT * FROM table WHERE age>%s AND id IN ({','.join(['%s']*len(params ),)})"
db.execute(stmt, tuple([age] + params))