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