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

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

При написании запросов в языке 1С часто возникает задача, когда из общего массива документов различного типа необходимо наложить отбор по реквизиту только на один конкретный вид документа (например, Документ.ПеремещениеТоваров), а все остальные типы документов выгрузить в выборку без изменений.

Разберем, в чем заключается логическая ошибка при составлении условных операторов в секции ГДЕ, и проанализируем правильные варианты решения задачи с точки зрения синтаксиса и производительности.

Суть проблемы и распространенная ошибка

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

  1. Если регистратор является документом ПеремещениеТоваров, в выборку должны попадать только те записи, у которых СкладОтправитель входит в массив &ВыбСкладыАБС.
  2. Если регистратор — любой другой документ (например, РеализацияТоваровУслуг или ПриходныйОрдерНаТовары), запись должна беспрепятственно попадать в результат.

Распространенная ошибка заключается в попытке использовать условную конструкцию ВЫБОР без ветки по умолчанию или в некорректном прямом наложении фильтра. Простая проверка склада отсечет все остальные типы документов, так как у них нет данного реквизита или условие вернет ЛОЖЬ.

Решение 1. Использование конструкции ВЫБОР КОГДА ... ИНАЧЕ ИСТИНА

Проанализируем первое решение с использованием конструкции ВЫБОР. Чтобы документы других типов не отсекались отбором, ветка ИНАЧЕ обязана возвращать булево значение ИСТИНА:


ГДЕ
	(ВЫБОР 
		КОГДА ТаблицаСписания.Регистратор ССЫЛКА Документ.ПеремещениеТоваров 
			ТОГДА ТаблицаСписания.Регистратор.СкладОтправитель В (&ВыбСкладыАБС)
		ИНАЧЕ ИСТИНА 
	КОНЕЦ)

Посмотрим, как вычисляется эта конструкция платформой:

  1. Если Регистратор относится к типу Документ.ПеремещениеТоваров, выполняется проверка СкладОтправитель В (&ВыбСкладыАБС). Результат отбора определяет, попадет ли строка в выборку.
  2. Если Регистратор относится к любому другому документу, срабатывает ветка ИНАЧЕ ИСТИНА, и условие в секции ГДЕ считается выполненным.

Решение 2. Использование логических операторов НЕ и ИЛИ

Эту же логику можно составить более лаконично, используя базовую логику операторов НЕ и ИЛИ без применения функции ВЫБОР:


ГДЕ
	НЕ ТаблицаСписания.Регистратор ССЫЛКА Документ.ПеремещениеТоваров
	ИЛИ ТаблицаСписания.Регистратор.СкладОтправитель В (&ВыбСкладыАБС)

Рассмотрим порядок вычисления данного выражения:

  1. Для всех документов, кроме перемещений, первая часть НЕ ... ССЫЛКА возвращает ИСТИНА. Поскольку используется оператор ИЛИ, вся цепочка условий сразу становится истинной.
  2. Для документа ПеремещениеТоваров первая часть возвращает ЛОЖЬ, поэтому СУБД переходит к проверке второго условия — совпадению склада со списком &ВыбСкладыАБС.

Оптимизация производительности: функция ВЫРАЗИТЬ

Разберем важный момент оптимизации. Если реквизит Регистратор имеет составной тип данных, прямое обращение к реквизиту через точку Регистратор.СкладОтправитель приводит к тому, что платформа 1С автоматически генерирует неявные соединения (LEFT JOIN) со всеми таблицами документов, входящих в данный составной тип.

Чтобы исключить лишние соединение и ускорить запрос, нужно явно указать тип с помощью функции ВЫРАЗИТЬ:


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

Использование ВЫРАЗИТЬ гарантирует, что неявное соединение будет сделано исключительно с таблицей документа «Перемещение товаров».

Оптимизация для высоконагруженных баз (ОБЪЕДИНИТЬ ВСЕ)

В крупных базах данных с миллионами записей оператор ИЛИ в секции ГДЕ может мешать оптимизатору СУБД использовать индексы. Если запрос работает медленно, эффективным решением станет разделение выборки на две части с помощью ОБЪЕДИНИТЬ ВСЕ:


// ВЫБОРКА 1: Все документы, кроме перемещений
ВЫБРАТЬ
	ТаблицаСписания.Регистратор КАК Регистратор,
	ТаблицаСписания.Количество КАК Количество
ИЗ
	РегистрНакопления.СебестоимостьТоваров КАК ТаблицаСписания
ГДЕ
	НЕ ТаблицаСписания.Регистратор ССЫЛКА Документ.ПеремещениеТоваров

ОБЪЕДИНИТЬ ВСЕ

// ВЫБОРКА 2: Только перемещения с отбором по складу
ВЫБРАТЬ
	ТаблицаСписания.Регистратор КАК Регистратор,
	ТаблицаСписания.Количество КАК Количество
ИЗ
	РегистрНакопления.СебестоимостьТоваров КАК ТаблицаСписания
ГДЕ
	ТаблицаСписания.Регистратор ССЫЛКА Документ.ПеремещениеТоваров
	И ВЫРАЗИТЬ(ТаблицаСписания.Регистратор КАК Документ.ПеремещениеТоваров).СкладОтправитель В (&ВыбСкладыАБС)

Такой подход позволяет СУБД построить оптимальные планы выполнения с точечным использованием индексов для каждой из частей запроса.

← На главную