В процессе разработки на платформе 1С часто возникает специфическая задача: необходимо сгруппировать записи (например, по штрихкоду), но при этом значение одного из ресурсов (например, коэффициента или цены) должно браться не как среднее или сумма, а строго из той строки, которая является наиболее актуальной на текущий момент (имеет максимальную дату). Более того, иногда требуется применить это "самое свежее" значение ко всем остальным записям в группе для выполнения дальнейших расчетов.
Разберем эту ситуацию на конкретном примере. Предположим, у нас есть таблица со следующими полями: КоличествоSellOut, _SUFactor, _Штрихкод и _ДатаАктивации. Наша цель — просуммировать _SUFactor таким образом, чтобы для каждой строки с одинаковым штрихкодом использовался фактор из записи с самой поздней датой активации.
Этот метод является классическим и наиболее универсальным для платформы 1С. Он стабильно работает на всех версиях 8.3 и эффективно использует возможности SQL-сервера. Разберем алгоритм по шагам.
Шаг 1: Подготовка временной таблицы с максимальными датами. Сначала нам нужно определить для каждого штрихкода, какая дата является максимальной, и посчитать общее количество записей, если это необходимо для итогового расчета.
ВЫБРАТЬ
Номенклатура._Штрихкод КАК _Штрихкод,
МАКСИМУМ(Номенклатура._ДатаАктивации) КАК МаксДатаАктивации,
СУММА(1) КАК КолЗаписей
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура._Штрихкод В (&МассивШтрихкодов)
СГРУППИРОВАТЬ ПО
Номенклатура._Штрихкод
;
Шаг 2: Получение итоговых данных. Теперь мы соединяем нашу временную таблицу с основной таблицей справочника (или регистра) по двум полям: штрихкоду и дате. Это позволяет нам "вытащить" значение _SUFactor, соответствующее именно этой максимальной дате.
ВЫБРАТЬ
ВТ._Штрихкод КАК _Штрихкод,
ВТ.МаксДатаАктивации КАК _ДатаАктивации,
ВТ.КолЗаписей * Номенклатура._SUFactor КАК СуммаСУфакторов
ИЗ
Справочник.Номенклатура КАК Номенклатура
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеДаты КАК ВТ
ПО ВТ._Штрихкод = Номенклатура._Штрихкод
И ВТ.МаксДатаАктивации = Номенклатура._ДатаАктивации
Проанализируем этот подход: мы сначала сжали данные до уникальных ключей (штрихкод + дата), а затем развернули их обратно, получив нужный коэффициент. Важный нюанс: если на одну и ту же секунду приходится две записи с разными факторами, внутреннее соединение может удвоить количество строк. Чтобы этого избежать, в группировку первой таблицы стоит добавить МАКСИМУМ(Ссылка) и во втором запросе соединяться по ссылке.
Если ваша база работает на современной версии платформы (8.3.21+), мы можем значительно упростить запрос, используя оконные функции. Это позволяет избежать создания временных таблиц и делает код более читаемым.
Рассмотрим, как это работает. Мы можем использовать функцию LAST_VALUE или FIRST_VALUE с определенным порядком сортировки внутри окна. Проанализируем пример логики:
PARTITION BY _Штрихкод.ORDER BY _ДатаАктивации DESC.Такой подход выполняется за один проход по индексам, что существенно экономит ресурсы сервера при работе с сотнями тысяч записей.
В некоторых случаях, когда создание временных таблиц нежелательно (например, в очень простых динамических списках), можно использовать подзапрос в списке выбора. Однако помните, что этот метод может быть медленным на больших объемах данных.
ВЫБРАТЬ
Т1._Штрихкод,
(ВЫБРАТЬ ПЕРВЫЕ 1 Т2._SUFactor
ИЗ Справочник.Номенклатура КАК Т2
ГДЕ Т2._Штрихкод = Т1._Штрихкод
УПОРЯДОЧИТЬ ПО Т2._ДатаАктивации УБЫВ) КАК АктуальныйФактор
ИЗ
Справочник.Номенклатура КАК Т1
Выясним причину, по которой этот метод стоит использовать с осторожностью: СУБД будет выполнять вложенный поиск для каждой строки основного запроса. Если в основной таблице 100 000 записей, сервер выполнит 100 000 мини-запросов. Поэтому для тяжелых отчетов всегда выбирайте Решение 1 с временными таблицами.
Для того чтобы любой из вышеперечисленных запросов летал, необходимо правильно настроить индексы. В нашем случае критически важен составной индекс по полям _Штрихкод + _ДатаАктивации.
Если данные хранятся в справочнике, убедитесь, что у реквизитов установлено свойство "Индексировать". Если же вы проектируете систему с нуля и вам часто требуется "самое свежее" значение, рассмотрите возможность использования Периодического регистра сведений. В 1С регистры сведений имеют виртуальную таблицу СрезПоследних, которая на уровне платформы оптимизирована именно под такие задачи. Вместо сложных соединений вы просто вызываете РегистрСведений.ИмяРегистра.СрезПоследних(&Дата, ...), и система сама возвращает актуальные коэффициенты.
Подведем итог: выбор метода зависит от версии вашей платформы и объема данных. Для большинства задач пакетный запрос с временной таблицей (где сначала ищется МАКСИМУМ(Дата)) остается "золотым стандартом" разработки на 1С.