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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке складских отчетов и процедур резервирования нередко возникает задача: отобрать обороты резервирования товаров за определенный период, но ограничить выборку исключительно теми позициями номенклатуры, которые на текущий момент (или на дату отчета) фактически имеются на складе. В типовых конфигурациях для этого используются два различных регистра накопления: регистр остатков товаров (например, ТоварыНаСкладах) и регистр резервов (например, ТоварыВРезервеНаСкладах).

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

Вариант 1. Использование временной таблицы с индексацией (рекомендуемый подход)

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


ВЫБРАТЬ РАЗРЕШЕННЫЕ
	ТоварыНаСкладахОстатки.Склад КАК Склад,
	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
	ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
ПОМЕСТИТЬ ВТ_ОстаткиТоваров
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, ) КАК ТоварыНаСкладахОстатки
ГДЕ
	ТоварыНаСкладахОстатки.КоличествоОстаток > 0

ИНДЕКСИРОВАТЬ ПО
	Номенклатура,
	Склад,
	ХарактеристикаНоменклатуры
;

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

Разберем по шагам ключевые детали реализации этого запроса:

  1. Отсутствие лишней группировки: Виртуальная таблица Остатки платформы 1С уже выдает свернутые и уникальные записи в разрезе указанных в секции ВЫБРАТЬ измерений. Применение конструкций СГРУППИРОВАТЬ ПО и секции ИМЕЮЩИЕ СУММА(...) > 0 избыточно дублирует работу платформы и создает неоправданную нагрузку на сервер. Для отсечения нулевых или отрицательных остатков достаточно простого условия в секции ГДЕ.
  2. Порядок полей в секции ИНДЕКСИРОВАТЬ ПО: При построении индекса временной таблицы критически важна селективность полей. Первым в списке индексации следует указывать измерение с наибольшим количеством уникальных значений — в данном случае Номенклатура, а затем уже Склад и ХарактеристикаНоменклатуры.
  3. Тип соединения: Так как цель задачи — получить обороты исключительно по позициям с остатком, используется ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Записи по товарам, которых нет во временной таблице остатков, будут автоматически исключены из результата.

Вариант 2. Прямое соединение виртуальных таблиц

В небольших базах или в простых обработках иногда применяют прямое соединение таблиц без создания временных таблиц в пакетном запросе:


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

Проанализируем специфику данного подхода и причины, по которым его следует использовать с осторожностью:

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

Важные нюансы передачи параметров в виртуальные таблицы

Выясним детали, от которых напрямую зависит корректность получаемых данных:

  1. Момент времени и объект Граница: Если в параметр &ДатаОстатков передать обычную дату без времени (или дату со временем без указания вида границы), платформа рассчитает остатки на начало указанной секунды. Чтобы движения документов, проведенных ровно в эту секунду, были включены в остаток, в коде встроенного языка следует передавать объект границы:
    
    Запрос.УстановитьПараметр("ДатаОстатков", Новый Граница(ДатаОтчета, ВидГраницы.Включая));
    
  2. Условия отбора в параметрах виртуальной таблицы: Если в отчете требуется отобрать данные по конкретному складу или списку номенклатуры, условия необходимо передавать во второй параметр виртуальных таблиц (УсловиеОтбора), а не в секции ГДЕ или ПО. Фильтрация внутри параметров виртуальной таблицы позволяет СУБД отсечь лишние записи на этапе обращения к агрегатам и таблицам итогов, что существенно ускоряет выполнение запроса.

Альтернативный вариант: отбор оборотов через условие в параметрах

Посмотрим на ситуацию, когда в итоговой выборке требуется получить только строки оборотов резервов, а само числовое значение остатка на складе выводить не нужно. В этом случае соединять таблицы вовсе не обязательно. Достаточно поместить номенклатуру с остатком во временную таблицу и передать подзапрос во второй параметр таблицы оборотов:


ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_ТоварыВОстатке
ИЗ
	РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, ) КАК ТоварыНаСкладахОстатки
ГДЕ
	ТоварыНаСкладахОстатки.КоличествоОстаток > 0

ИНДЕКСИРОВАТЬ ПО
	Номенклатура
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
	ТоварыВРезервеНаСкладахОбороты.Склад КАК Склад,
	ТоварыВРезервеНаСкладахОбороты.Номенклатура КАК Номенклатура,
	ТоварыВРезервеНаСкладахОбороты.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	ТоварыВРезервеНаСкладахОбороты.КоличествоПриход КАК КоличествоПриход,
	ТоварыВРезервеНаСкладахОбороты.КоличествоРасход КАК КоличествоРасход
ИЗ
	РегистрНакопления.ТоварыВРезервеНаСкладах.Обороты(
		&НачалоПериода,
		&КонецПериода,
		Авто,
		Номенклатура В (ВЫБРАТЬ Т.Номенклатура ИЗ ВТ_ТоварыВОстатке КАК Т)
	) КАК ТоварыВРезервеНаСкладахОбороты

Такой способ минимизирует объем считываемых данных из регистра резервов еще на этапе обращения к базе данных и исключает необходимость наложения соединений.

← На главную