Зачастую перед разработчиками 1С встает нетривиальная задача: имеется таблица с номенклатурой, датой установки и сроком полезного использования в месяцах. Нужно получить список всех будущих дат замены для каждой позиции в рамках заданного периода. Так как язык запросов 1С является декларативным, прямого цикла в нем нет, и мы сейчас разберем, как эффективно решить эту проблему.
Самый наглядный способ — это создание вспомогательной временной таблицы, содержащей список всех месяцев в периоде. Мы можем получить их из РегламентированныйПроизводственныйКалендарь или сгенерировать программно.
Разберем логику:
Календарь, содержащую начало каждого месяца в заданном интервале.
ВЫБРАТЬ НАЧАЛОПЕРИОДА(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря, МЕСЯЦ) КАК Месяц
ПОМЕСТИТЬ Календарь
ИЗ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ РегламентированныйПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &ДатаНачала И &ДатаОкончания
СГРУППИРОВАТЬ ПО НАЧАЛОПЕРИОДА(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря, МЕСЯЦ);
ВЫБРАТЬ ИсходнаяТаблица.Номенклатура, ИсходнаяТаблица.ДатаУстановки, Календарь.Месяц
ИЗ ИсходнаяТаблица КАК ИсходнаяТаблица, Календарь КАК Календарь
ГДЕ РАЗНОСТЬДАТ(ИсходнаяТаблица.ДатаУстановки, Календарь.Месяц, МЕСЯЦ) % ИсходнаяТаблица.СрокПолезногоИспользования = 0
И Календарь.Месяц > ИсходнаяТаблица.ДатаУстановки;
Если календарь использовать неудобно, мы можем сгенерировать таблицу чисел (от 1 до N) внутри запроса и использовать их как множители для интервалов. Этот способ более универсален и не привязан к конкретным регистрам данных.
Пошаговый алгоритм:
втЧислоПовторений, содержащую числа от 1 до 12 (или больше, если период велик).РАЗНОСТЬДАТ и деление на срок использования.ДатаУстановки результат произведения СрокПолезногоИспользования * ЧислоПовторений.
ВЫБРАТЬ 1 КАК ЧислоПовторений ПОМЕСТИТЬ втЧислоПовторений
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 ... // и так далее до нужного количества
ВЫБРАТЬ ИсходнаяТаблица.Номенклатура,
ДОБАВИТЬКДАТЕ(ИсходнаяТаблица.ДатаУстановки, МЕСЯЦ, ИсходнаяТаблица.СрокПолезногоИспользования * втЧислоПовторений.ЧислоПовторений) КАК ДатаЗамены
ИЗ ИсходнаяТаблица КАК ИсходнаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ втЧислоПовторений КАК втЧислоПовторений
ПО (втЧислоПовторений.ЧислоПовторений <= ИсходнаяТаблица.МаксЧислоЗамен);
При реализации подобных задач всегда помните о производительности:
ГДЕ или в соединениях, чтобы уменьшить объем промежуточных данных.ИНДЕКСИРОВАТЬ ПО, которая значительно ускоряет выполнение последующих соединений.Рассмотренные способы позволяют решить задачу средствами языка запросов 1С без написания тяжелых циклов в коде модуля. Выбор метода зависит от того, насколько гибким должен быть интервал и каков объем данных в вашей системе.