При разработке отчетов и обработок в платформе 1С:Предприятие часто возникает задача ограничить выборку регистра или таблицы движений только определенными видами документов-регистраторов. В языке запросов 1С проверка принадлежности ссылки конкретному типу обычно выполняется оператором ССЫЛКА. Однако передать простой список метаданных напрямую в конструкцию ССЫЛКА нельзя. Разберем основные способы реализации отбора по нескольким видам документов, а также выясним особенности их влияния на производительность базы данных.
Рассмотрим наиболее гибкий вариант, при котором список нужных видов документов формируется во встроенном языке и передается в запрос в виде параметра. В языке запросов 1С доступна функция ТИПЗНАЧЕНИЯ, позволяющая получить тип поля составного типа и сравнить его со списком типов.
Посмотрим на пример формирования параметров и текста запроса во встроенном языке:
СписокТипов = Новый Массив;
СписокТипов.Добавить(Тип("ДокументСсылка.ОтчетОРозничныхПродажах"));
СписокТипов.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
СписокТипов.Добавить(Тип("ДокументСсылка.ПеремещениеТоваров"));
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Партии.Регистратор КАК Регистратор,
| Партии.Номенклатура КАК Номенклатура,
| Партии.КоличествоОборот КАК КоличествоОборот
|ИЗ
| РегистрНакопления.ПартииТоваровНаСкладах.Обороты(
| ,
| ,
| Авто,
| ТИПЗНАЧЕНИЯ(Регистратор) В (&СписокТипов)) КАК Партии";
Запрос.УстановитьПараметр("СписокТипов", СписокТипов);
РезультатЗапроса = Запрос.Выполнить();
Проанализируем работу этого механизма: на уровне СУБД поле составного типа (включая Регистратор) физически разделяется на колонку кода типа метаданных (TRef) и колонку уникального идентификатора ссылки (RRef). Конструкция ТИПЗНАЧЕНИЯ(Поле) В (&СписокТипов) на уровне базы данных выполняет фильтрацию непосредственно по колонке TRef, что позволяет быстро отсекать записи без необходимости соединения со всеми таблицами метаданных.
Классическим и наиболее наглядным методом в тексте запроса является явное перечисление всех допустимых видов документов с помощью логического ИЛИ. В языке запросов оператор ССЫЛКА требует явного указания имени таблицы метаданных через точку.
Посмотрим, как выглядит условие отбора при явном указании документов:
ВЫБРАТЬ
Партии.Регистратор КАК Регистратор,
Партии.Номенклатура КАК Номенклатура,
Партии.КоличествоОборот КАК КоличествоОборот
ИЗ
РегистрНакопления.ПартииТоваровНаСкладах.Обороты(
,
,
Авто,
Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
ИЛИ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ИЛИ Регистратор ССЫЛКА Документ.ПеремещениеТоваров) КАК Партии
Разберем плюсы и минусы данного подхода:
Если необходимо использовать быстрый оператор ССЫЛКА, но точный список видов документов определяется во время работы программы, сформируем фрагмент запроса динамически с помощью встроенного языка 1С.
Рассмотрим пример генерации условия:
МассивИменДокументов = Новый Массив;
МассивИменДокументов.Добавить("ОтчетОРозничныхПродажах");
МассивИменДокументов.Добавить("РеализацияТоваровУслуг");
МассивУсловий = Новый Массив;
Для Каждого ИмяДокумента Из МассивИменДокументов Цикл
МассивУсловий.Добавить("Регистратор ССЫЛКА Документ." + ИмяДокумента);
КонецЦикла;
УсловиеПоТипам = СтрСоединить(МассивУсловий, " ИЛИ ");
ТекстЗапроса =
"ВЫБРАТЬ
| Партии.Регистратор КАК Регистратор,
| Партии.КоличествоОборот КАК КоличествоОборот
|ИЗ
| РегистрНакопления.ПартииТоваровНаСкладах.Обороты(, , Авто, " + УсловиеПоТипам + ") КАК Партии";
Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить();
При фильтрации по регистратору и его типу обязательно учитываем следующие архитектурные правила платформы 1С:
УсловиеОтбора), а не в секции ГДЕ. Если написать отбор в ГДЕ, СУБД сначала рассчитает все обороты по всей базе данных и лишь затем отфильтрует строки, что приведет к существенному падению производительности.Регистратор доступно в виртуальных таблицах Обороты и ОстаткиИОбороты только тогда, когда периодичность задана как Регистратор или Авто. В таблицах остатков поле Регистратор отсутствует.