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

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

При разработке отчетов по маркетинговым активностям часто возникает задача вывести периоды действия скидок в формате «Дата начала — Дата окончания». В типовых конфигурациях, таких как 1С:Управление торговлей 11 или 1С:ERP, информация о статусах скидок хранится в периодическом регистре сведений ДействиеСкидокНаценок. Однако попытка получить эти данные простым запросом к виртуальной таблице часто оборачивается логическими ошибками или техническими трудностями в конструкторе запросов.

В этой статье мы подробно разберем, почему не стоит использовать срез последних для истории, как справиться с «противоречивыми связями» при работе с составными типами и как правильно состыковать записи о включении и отключении скидок.

Разбор основной ошибки: Почему «СрезПоследних» не подходит для отчета за период

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

Виртуальная таблица СрезПоследних предназначена для получения состояния на одну конкретную точку во времени. Она не хранит историю переключений. Для построения отчета, который показывает, когда скидка началась и когда закончилась, необходимо обращаться к основной (физической) таблице регистра сведений. Только там содержатся все записи об изменениях, которые мы сможем сопоставить друг с другом.

Проблема составных типов и ошибка «Противоречивая связь»

В регистре ДействиеСкидокНаценок измерение Источник часто имеет составной тип данных (например, Справочник.СоглашенияСКлиентами, Справочник.СегментыПартнеров и другие). При попытке объединить или соединить таблицы по такому полю в Конструкторе запросов 1С может возникнуть ошибка «Противоречивая связь».

Это происходит потому, что Конструктор пытается сопоставить метаданные полей, и если типы в разных временных таблицах определены неявно, он выдает предупреждение. Чтобы этого избежать, проанализируем использование оператора ВЫБОР. Вместо сложной конструкции с проверкой ссылки лучше использовать оператор ВЫРАЗИТЬ. Это не только успокоит Конструктор, но и оптимизирует работу СУБД, так как ей не придется сканировать все таблицы, входящие в составной тип.

Пример правильной типизации поля Источник:


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

Алгоритм «Стыковки» периодов: соединяем Начало и Конец

Чтобы получить одну строку с датой начала и датой окончания, мы должны выполнить самосоединение таблицы регистра. Проанализируем логику: для каждой записи, где статус равен «Действует», нам нужно найти самую раннюю следующую по времени запись с тем же соглашением и скидкой, но со статусом «Не действует».

Разберем по шагам создание такого запроса:

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

Посмотрим на практический пример реализации этого алгоритма:


ВЫБРАТЬ
    Действует.Источник КАК Источник,
    Действует.СкидкаНаценка КАК СкидкаНаценка,
    Действует.Период КАК ДатаНачала,
    МИНИМУМ(НеДействует.Период) КАК ДатаОкончания
ИЗ
    РегистрСведений.ДействиеСкидокНаценок КАК Действует
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДействиеСкидокНаценок КАК НеДействует
        ПО Действует.Источник = НеДействует.Источник
            И Действует.СкидкаНаценка = НеДействует.СкидкаНаценка
            И НеДействует.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДействияСкидок.НеДействует)
            И Действует.Период < НеДействует.Период
ГДЕ
    Действует.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДействияСкидок.Действует)

СГРУППИРОВАТЬ ПО
    Действует.Источник,
    Действует.СкидкаНаценка,
    Действует.Период

Обработка пустых дат окончания

В реальной базе данных многие скидки могут действовать «бессрочно» на текущий момент. В этом случае ЛЕВОЕ СОЕДИНЕНИЕ не найдет запись со статусом «Не действует», и поле ДатаОкончания будет содержать NULL. Чтобы отчет выглядел корректно, проанализируем ситуацию и подставим пустую дату или «бесконечность» (например, 31.12.3999) с помощью функции ЕСТЬNULL.

Современный подход: Использование оконных функций (Платформа 8.3.21+)

Если вы работаете на современной версии платформы 1С (8.3.21 и выше), задачу можно решить значительно эффективнее с помощью оконных функций. Это избавит базу данных от тяжелого соединения таблиц саму с собой.

Рассмотрим, как это работает: функция LEAD позволяет «заглянуть» в следующую строку выборки. Мы можем сгруппировать данные по скидке и источнику, отсортировать по периоду и сразу получить период следующей записи.


ВЫБРАТЬ
    Источник,
    СкидкаНаценка,
    Статус,
    Период КАК ДатаНачала,
    LEAD(Период) OVER (PARTITION BY Источник, СкидкаНаценка ORDER BY Период) КАК ДатаОкончания
ИЗ
    РегистрСведений.ДействиеСкидокНаценок
ГДЕ
    Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДействияСкидок.Действует)

Важный нюанс: Оконные функции работают очень быстро, но они доступны только при определенных настройках режима совместимости конфигурации. Если ваша база находится на старой версии, используйте классический метод с МИНИМУМ и группировкой, описанный выше.

Заключение и рекомендации

Подведем итоги нашего анализа. Для корректного построения периодов действия объектов в 1С придерживайтесь следующих правил:

Используя эти методы, вы сможете строить точные и производительные отчеты по любым периодическим регистрам сведений, будь то цены номенклатуры, статусы скидок или курсы валют.

← На главную