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

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

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

При попытке прописать подзапрос с конструкцией ВЫБРАТЬ непосредственно в параметрах виртуальной таблицы (например, Период >= МИНИМУМ(ВЫБРАТЬ ...)) платформа 1С выдает сообщение: "Синтаксическая ошибка Выбрать".

Выясним причину этой ошибки. В языке запросов 1С действуют следующие ограничения:

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

Рассмотрим подробнее три основных способа решения этой задачи.

Способ 1. Вычисление минимального периода и передача через параметр (Рекомендуемый)

Разберем наиболее оптимальный способ с точки зрения производительности СУБД. Сначала отдельным или предварительным запросом вычисляется минимальная дата из временной таблицы, сохраняется в переменную 1С и передается в основной запрос в качестве параметра.

Посмотрим на пример реализации во встроенном языке 1С:


// Шаг 1. Вычисляем минимальную дату из временной таблицы
ЗапросМин = Новый Запрос;
ЗапросМин.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросМин.Текст = 
    "ВЫБРАТЬ
    |	МИНИМУМ(ВремТаб.Период) КАК МинПериод
    |ИЗ
    |	ВремТаб КАК ВремТаб";

Выборка = ЗапросМин.Выполнить().Выбрать();
Если Выборка.Следующий() И ЗначениеЗаполнено(Выборка.МинПериод) Тогда
    МинДата = Выборка.МинПериод;
Иначе
    МинДата = Дата(1, 1, 1);
КонецЕсли;

// Шаг 2. Передаем значение в параметр основного запроса
ЗапросОсновной = Новый Запрос;
ЗапросОсновной.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросОсновной.УстановитьПараметр("МинПериод", МинДата);
ЗапросОсновной.Текст = 
    "ВЫБРАТЬ
    |	Остатки.Номенклатура КАК Номенклатура,
    |	Остатки.КоличествоОборот КАК Количество
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Обороты(&МинПериод, , , ) КАК Остатки";

Преимущество метода: Платформа 1С накладывает отбор на самом раннем этапе формирования выборки СУБД, что обеспечивает наивысшую скорость выполнения.

Способ 2. Использование подзапроса в секции ГДЕ

Если запрос формируется без разбиения на исполнение в коде 1С, подзапрос с агрегатной функцией можно вынести из параметров виртуальной таблицы в секцию ГДЕ основного запроса (или выполнять выборку из реальной таблицы регистра):


ВЫБРАТЬ
	ОсновнаяТаблица.Период КАК Период,
	ОсновнаяТаблица.Регистратор КАК Регистратор
ИЗ
	РегистрСведений.ИсполнениеЗадач КАК ОсновнаяТаблица
ГДЕ
	ОсновнаяТаблица.Период >=
		(ВЫБРАТЬ
			МИНИМУМ(ВТ.Период)
		ИЗ
			ВремТаб КАК ВТ)

Обратите внимание: использование отбора в секции ГДЕ при работе с виртуальными таблицами может приводить к снижению производительности, так как СУБД сначала формирует выборку виртуальной таблицы, а затем отсекает лишние записи.

Способ 3. Внутреннее соединение с временной таблицей

Проанализируем подход, который реализуется полностью в одном пакетном запросе без использования кода 1С.

Разберем алгоритм по шагам:

  1. Формируем временную таблицу, содержащую одну строку с минимальным периодом.
  2. Соединяем основную таблицу с созданной временной таблицей через ВНУТРЕННЕЕ СОЕДИНЕНИЕ по условию сравнения дат.

Рассмотрим пример пакета запросов:


ВЫБРАТЬ
	МИНИМУМ(ВремТаб.Период) КАК МинПериод
ПОМЕСТИТЬ ВТ_МинПериод
ИЗ
	ВремТаб КАК ВремТаб;

ВЫБРАТЬ
	Регистр.Период КАК Период,
	Регистр.Ресурс КАК Ресурс
ИЗ
	РегистрСведений.КурсыВалют КАК Регистр
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МинПериод КАК ВТ_Мин
		ПО Регистр.Период >= ВТ_Мин.МинПериод

Для достижения наилучшей производительности при работе с большими объемами данных всегда рекомендуется использовать Способ 1 с передачей готового значения через параметр &МинПериод.

← На главную