Задать вопрос
@ArtiomK

Как сделать конструкцию IN %(param_name)s необязательным параметром в строке sql если в качестве значения параметра был предоставлен пустой массив?

Я хочу сделать IN %(param_name)s необязательно частью запроса PostgreSQL (деактевировать фильтр) если в качестве значения параметра был предоставлен пустой массив, получаем все значения, как если бы фильтра для данного параметра не было. То есть выражение
"SELECT * FROM table_name WHERE cam_id IN %(param_name)s;"
будет тождественно "SELECT * FROM table_name; "

Если возможных значений для param_name в Питоне мало, я могу обойти проблему передавая дефолтный список вместо пустого направленного а АПИ. Но я хочу узнать как это делать верно (без костылей).

Пример:

query ="""
SELECT 
 id, cam_id
 FROM sometable
 WHERE id > %(_id)s
 // if use = instead of IN, it works well (of course if cameras is just one value, not array)
 AND (%(camera)s is NULL OR cam_id IN %(camera)s);"""

values = {"_id": 10, camera: tuple(1, 2, 3)]}
curs.execute(query, values)


Какие я получаю ошибки если tuple пустой:
psycopg2.errors.SyntaxError: syntax error at or near ")" LINE 6: WHERE (() is NULL OR cam_id IN ()


Примечание, если заменить IN на = и передавать одиночные значения (не массив), то все отлично работает.

Ранее задавал вопрос здесь
  • Вопрос задан
  • 126 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 1
Melkij
@Melkij
PostgreSQL DBA
Не надо так делать.
https://use-the-index-luke.com/sql/where-clause/ob...

Не включайте в запрос условие, если его там не должно быть.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@galaxy
Если не хотите руками собирать запросы (или с помощью модуля sql), можно использовать списки:
v = {'_id': 10, 'param_name': None}
c.mogrify("SELECT * FROM table_name WHERE %(param_name)s IS NULL OR id = ANY(%(param_name)s)", v)
# b'SELECT * FROM table_name WHERE NULL IS NULL OR id = ANY(NULL)'

v = {"_id": 10, "param_name": [1, 2, 3]}
# b'SELECT * FROM table_name WHERE ARRAY[1,2,3] IS NULL OR id = ANY(ARRAY[1,2,3])'


Вместо None можно и под пустой список подогнать (немного больше возни):
v = {"_id": 10, "param_name": []}
c.mogrify("SELECT * FROM table_name WHERE cardinality(%(param_name)s::int[]) = 0 OR id = ANY(%(param_name)s)", v)
# b"SELECT * FROM table_name WHERE cardinality('{}'::int[]) = 0 OR id = ANY('{}')"
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы