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

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

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

Типичные ошибки при получении последних движений

Рассмотрим характерные ошибки, которые часто допускаются в попытках получить последнюю запись из регистра накопления ТоварыНаСкладах:

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

Вариант 1. Получение только максимальной даты прихода

Если перед нами стоит простая задача — узнать только дату последнего поступления номенклатуры на заданный склад без привязки к конкретному регистратору и количеству, достаточно использовать агрегатную функцию МАКСИМУМ и сгруппировать результат по измерению Номенклатура.

Посмотрим на пример правильного компактного запроса:


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

Обратим внимание на следующие оптимизации в тексте запроса:

  1. Мы избавились от вложенного запроса и соединений со справочником номенклатуры — реквизит Артикул выбирается напрямую через точку от ссылки измерения регистра.
  2. Условие ТоварыНаСкладах.Номенклатура.ЭтоГруппа = ЛОЖЬ заменено на более быстрое и устойчивое к значениям NULL выражение НЕ ТоварыНаСкладах.Номенклатура.ЭтоГруппа.
  3. Вместо жесткой проверки конкретного типа документа (ССЫЛКА Документ.ПоступлениеТоваровУслуг) используется проверка ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход), что позволяет корректно учитывать все приходные операции (включая оприходования, перемещения и возвраты).

Вариант 2. Получение документа, количества и реквизитов последней поставки

Когда требуется вывести не только дату, но и конкретный документ поступления (поле Регистратор), а также количество из этого документа, группировка в один этап не подойдет. Для этого используется классический двухэтапный паттерн с временными таблицами в пакетном запросе.

Разберем по шагам логику решения:

  1. Первый запрос пакета: отбираем движения прихода, группируем их по номенклатуре и складу, вычисляем МАКСИМУМ(Период) и помещаем полученные данные во временную таблицу с обязательным индексированием.
  2. Второй запрос пакета: связываем таблицу движений регистра с созданной временной таблицей по полям Номенклатура, Склад и Период, извлекая детальные данные последнего документа.

Посмотрим на пример готового пакетного запроса:


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

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

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

Защита от дублирования строк при совпадении дат

Проанализируем потенциальную проблему: если по одной номенклатуре в одну и ту же секунду (один Период) проведено два документа поступления, соединение вернет две строки. Чтобы гарантировать уникальность строки по товару, можно применить дополнительное ограничение: определять максимум не только по периоду, но и по ссылке на регистратор (при условии, что СУБД упорядочивает ссылки), либо добавить группировку по регистратору во втором запросе пакета через МАКСИМУМ(ТоварыНаСкладах.Регистратор).

Рекомендации по оптимизации запросов к регистрам

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

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