Получение информации о последнем поступлении товара на склад — одна из самых частых задач при разработке отчетов и обработок в среде 1С:Предприятие. Начинающие разработчики нередко сталкиваются с ошибками при построении таких запросов: некорректное использование агрегатных функций, ошибки синтаксиса группировки и неоптимальные соединения. Разберем типичные ошибки, проанализируем причины их возникновения и рассмотрим правильные варианты реализации задачи.
Рассмотрим характерные ошибки, которые часто допускаются в попытках получить последнюю запись из регистра накопления ТоварыНаСкладах:
Наименование вместо ссылки приводит к колоссальному падению производительности и ошибкам из-за дублей или опечаток в наименованиях.Родитель.Родитель.Родитель: попытка развернуть иерархию вручную через цепочки обращений к родителям утяжеляет код. Для выборки иерархических данных предназначен оператор В ИЕРАРХИИ.МАКСИМУМ(Период) и одновременно включить в список полей и секцию СГРУППИРОВАТЬ ПО поле Регистратор, запрос вернет не одну последнюю дату по товару, а абсолютно все документы прихода, так как каждый документ имеет уникальную ссылку.МАКСИМУМ() без указания секции СГРУППИРОВАТЬ ПО вызывает синтаксическую ошибку платформы: «Поле не входит в группу».Если перед нами стоит простая задача — узнать только дату последнего поступления номенклатуры на заданный склад без привязки к конкретному регистратору и количеству, достаточно использовать агрегатную функцию МАКСИМУМ и сгруппировать результат по измерению Номенклатура.
Посмотрим на пример правильного компактного запроса:
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Номенклатура.Артикул КАК Артикул,
МАКСИМУМ(ТоварыНаСкладах.Период) КАК ДатаПоследнегоПрихода
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
ТоварыНаСкладах.Склад = &Склад
И ТоварыНаСкладах.Номенклатура В ИЕРАРХИИ(&Родитель)
И НЕ ТоварыНаСкладах.Номенклатура.ЭтоГруппа
И ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Номенклатура.Артикул
Обратим внимание на следующие оптимизации в тексте запроса:
Артикул выбирается напрямую через точку от ссылки измерения регистра.ТоварыНаСкладах.Номенклатура.ЭтоГруппа = ЛОЖЬ заменено на более быстрое и устойчивое к значениям NULL выражение НЕ ТоварыНаСкладах.Номенклатура.ЭтоГруппа.ССЫЛКА Документ.ПоступлениеТоваровУслуг) используется проверка ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход), что позволяет корректно учитывать все приходные операции (включая оприходования, перемещения и возвраты).Когда требуется вывести не только дату, но и конкретный документ поступления (поле Регистратор), а также количество из этого документа, группировка в один этап не подойдет. Для этого используется классический двухэтапный паттерн с временными таблицами в пакетном запросе.
Разберем по шагам логику решения:
МАКСИМУМ(Период) и помещаем полученные данные во временную таблицу с обязательным индексированием.Номенклатура, Склад и Период, извлекая детальные данные последнего документа.Посмотрим на пример готового пакетного запроса:
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Склад КАК Склад,
МАКСИМУМ(ТоварыНаСкладах.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
ТоварыНаСкладах.Склад = &Склад
И ТоварыНаСкладах.Номенклатура В ИЕРАРХИИ(&Родитель)
И НЕ ТоварыНаСкладах.Номенклатура.ЭтоГруппа
И ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Склад
ИНДЕКСИРОВАТЬ ПО
Номенклатура,
Склад,
МаксПериод
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_МаксимальныеДаты.Номенклатура КАК Номенклатура,
ВТ_МаксимальныеДаты.Номенклатура.Артикул КАК Артикул,
ВТ_МаксимальныеДаты.Склад КАК Склад,
ВТ_МаксимальныеДаты.МаксПериод КАК ДатаПрихода,
ТоварыНаСкладах.Регистратор КАК ДокументПрихода,
ТоварыНаСкладах.Количество КАК Количество
ИЗ
ВТ_МаксимальныеДаты КАК ВТ_МаксимальныеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ПО ВТ_МаксимальныеДаты.Номенклатура = ТоварыНаСкладах.Номенклатура
И ВТ_МаксимальныеДаты.Склад = ТоварыНаСкладах.Склад
И ВТ_МаксимальныеДаты.МаксПериод = ТоварыНаСкладах.Период
ГДЕ
ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
Проанализируем потенциальную проблему: если по одной номенклатуре в одну и ту же секунду (один Период) проведено два документа поступления, соединение вернет две строки. Чтобы гарантировать уникальность строки по товару, можно применить дополнительное ограничение: определять максимум не только по периоду, но и по ссылке на регистратор (при условии, что СУБД упорядочивает ссылки), либо добавить группировку по регистратору во втором запросе пакета через МАКСИМУМ(ТоварыНаСкладах.Регистратор).
Для обеспечения максимального быстродействия запросов в высоконагруженных базах соблюдаем следующие правила:
ИНДЕКСИРОВАТЬ ПО критически важна при соединении с большими реальными таблицами регистров.В ИЕРАРХИИ накладывается на большой каталог, предпочтительно сначала выбрать список ссылок номенклатуры в отдельную временную таблицу, а затем соединять её с регистром.СрезПоследних.