Как в запросе 1С сделать отбор по нескольким видам документов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов и обработок в платформе 1С:Предприятие часто возникает задача ограничить выборку регистра или таблицы движений только определенными видами документов-регистраторов. В языке запросов 1С проверка принадлежности ссылки конкретному типу обычно выполняется оператором ССЫЛКА. Однако передать простой список метаданных напрямую в конструкцию ССЫЛКА нельзя. Разберем основные способы реализации отбора по нескольким видам документов, а также выясним особенности их влияния на производительность базы данных.

Способ 1. Использование функции ТИПЗНАЧЕНИЯ и передача списка типов в параметры

Рассмотрим наиболее гибкий вариант, при котором список нужных видов документов формируется во встроенном языке и передается в запрос в виде параметра. В языке запросов 1С доступна функция ТИПЗНАЧЕНИЯ, позволяющая получить тип поля составного типа и сравнить его со списком типов.

Посмотрим на пример формирования параметров и текста запроса во встроенном языке:


СписокТипов = Новый Массив;
СписокТипов.Добавить(Тип("ДокументСсылка.ОтчетОРозничныхПродажах"));
СписокТипов.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
СписокТипов.Добавить(Тип("ДокументСсылка.ПеремещениеТоваров"));

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Партии.Регистратор КАК Регистратор,
    |	Партии.Номенклатура КАК Номенклатура,
    |	Партии.КоличествоОборот КАК КоличествоОборот
    |ИЗ
    |	РегистрНакопления.ПартииТоваровНаСкладах.Обороты(
    |			,
    |			,
    |			Авто,
    |			ТИПЗНАЧЕНИЯ(Регистратор) В (&СписокТипов)) КАК Партии";

Запрос.УстановитьПараметр("СписокТипов", СписокТипов);
РезультатЗапроса = Запрос.Выполнить();

Проанализируем работу этого механизма: на уровне СУБД поле составного типа (включая Регистратор) физически разделяется на колонку кода типа метаданных (TRef) и колонку уникального идентификатора ссылки (RRef). Конструкция ТИПЗНАЧЕНИЯ(Поле) В (&СписокТипов) на уровне базы данных выполняет фильтрацию непосредственно по колонке TRef, что позволяет быстро отсекать записи без необходимости соединения со всеми таблицами метаданных.

Способ 2. Использование оператора ССЫЛКА с логическим оператором ИЛИ

Классическим и наиболее наглядным методом в тексте запроса является явное перечисление всех допустимых видов документов с помощью логического ИЛИ. В языке запросов оператор ССЫЛКА требует явного указания имени таблицы метаданных через точку.

Посмотрим, как выглядит условие отбора при явном указании документов:


ВЫБРАТЬ
	Партии.Регистратор КАК Регистратор,
	Партии.Номенклатура КАК Номенклатура,
	Партии.КоличествоОборот КАК КоличествоОборот
ИЗ
	РегистрНакопления.ПартииТоваровНаСкладах.Обороты(
			,
			,
			Авто,
			Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
				ИЛИ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
				ИЛИ Регистратор ССЫЛКА Документ.ПеремещениеТоваров) КАК Партии

Разберем плюсы и минусы данного подхода:

  1. Наглядность: текст запроса статичен, самодостаточен и не требует обязательного заполнения специальных массивов типов перед выполнением.
  2. Ограничения динамики: если список видов документов должен выбираться пользователем динамически в интерфейсе программы, жестко прописанный текст запроса придется собирать программно.

Способ 3. Динамическое формирование текста условий во встроенном языке

Если необходимо использовать быстрый оператор ССЫЛКА, но точный список видов документов определяется во время работы программы, сформируем фрагмент запроса динамически с помощью встроенного языка 1С.

Рассмотрим пример генерации условия:


МассивИменДокументов = Новый Массив;
МассивИменДокументов.Добавить("ОтчетОРозничныхПродажах");
МассивИменДокументов.Добавить("РеализацияТоваровУслуг");

МассивУсловий = Новый Массив;
Для Каждого ИмяДокумента Из МассивИменДокументов Цикл
    МассивУсловий.Добавить("Регистратор ССЫЛКА Документ." + ИмяДокумента);
КонецЦикла;

УсловиеПоТипам = СтрСоединить(МассивУсловий, " ИЛИ ");

ТекстЗапроса = 
    "ВЫБРАТЬ
    |	Партии.Регистратор КАК Регистратор,
    |	Партии.КоличествоОборот КАК КоличествоОборот
    |ИЗ
    |	РегистрНакопления.ПартииТоваровНаСкладах.Обороты(, , Авто, " + УсловиеПоТипам + ") КАК Партии";

Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить();

Важные правила оптимизации запросов к регистрам

При фильтрации по регистратору и его типу обязательно учитываем следующие архитектурные правила платформы 1С:

  1. Передача условий в параметры виртуальной таблицы: любые условия по типу или ссылкам регистратора необходимо указывать исключительно в четвертом параметре виртуальной таблицы (УсловиеОтбора), а не в секции ГДЕ. Если написать отбор в ГДЕ, СУБД сначала рассчитает все обороты по всей базе данных и лишь затем отфильтрует строки, что приведет к существенному падению производительности.
  2. Периодичность виртуальной таблицы: поле Регистратор доступно в виртуальных таблицах Обороты и ОстаткиИОбороты только тогда, когда периодичность задана как Регистратор или Авто. В таблицах остатков поле Регистратор отсутствует.
  3. Отборы в Системе компоновки данных (СКД): если отчет строится на базе СКД, отбор по регистратору настраивается на вкладке «Настройки» через сравнение вида «В списке по типу», где платформа позволяет интерактивно выбрать нужные виды документов.
← На главную