Уважаемые коллеги,
в класс BasicCursor Celesta добавился новый метод фильтрации: setIn, который позволяет установить фильтр с вложенным запросом по указанному набору полей.
Хорошо знакомый метод setFilter позволяет фильтровать записи, некоторое поле которых принимает любое значение из заранее заданного набора. К примеру,
myCursor.setFilter('city_id', "'MSK'|'LON'")отфильтровывает записи, поле «код города» которых принимает значение MSK или LON. Вызов
myCursor.setFilter('city_id', "'M'%")
Но функциональности setFilter бывает недостаточно: что если необходимо отфильтровать записи, относящиеся к городам, полное название которых на русском языке начинается с буквы «Ф»?
Одним из способов решения такой задачи может быть следующее:
отфильтровать справочник городов по city.setFilter('name',
"'Ф'%"), далее выгрузить из базы данных в память полный набор
идентификаторов таких городов, объединить их в строку фильтра
через вертикальную черту, и использовать это как фильтр на другом
курсоре. Ясно, что такой подход плох, если попадающих в фильтр
записей слишком много: это породит обмен лишними данными по сети и
слишком длинный SQL-запрос к интересующей нас таблице.
Именно для такого случая и можно теперь применять метод setIn.
Общая схема работы с setIn такова:
Связь полей задается при помощи вспомогательного класса FieldsLookup, принимающего в метод конструктора два курсора, по которым ищется пересечение. Первым аргументом должен быть указан фильтруемый, а вторым — фильтрующий курсор. Создание объекта и аккумулирование пар столбцов с последующей установкой фильтра происходит следующим образом:
from ru.curs.celesta.dbutils.filter.value import FieldsLookup from _filters_orm import FilteringCursor, FilteredCursor a = FilteringCursor(context) a.setRange('foo', 'bar') b = FilteredCursor(context) lookup = FieldsLookup(a, b).add("a1", "b1").add("a2", "b2") a.setIn(lookup)
Для данного примера в PostgreSQL, например, для доступа к строкам
курсора a будет сгенерировано следующее sql выражение:
SELECT ... FROM Filtered WHERE ( a1, a2 ) IN (SELECT b1, b2 FROM Filtering WHERE Filtering.foo = 'bar' )Ограничения
У данного фильтра имеется набор ограничений, несоблюдение которых приведёт к выбрасыванию исключения во время выполнения методов FieldsLookup.add или BasicCursor.setIn:
lookup = FieldsLookup(a, b).add("a2", "b2") a.setIn(lookup)
Возможность доступна в trunk-версии. Wiki-документация обновлена. С уважением, Иван Головко, Иван Пономарёв