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

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

В практике разработки на платформе 1С часто возникает задача: вывести в печатную форму или отчет данные, которые менялись в течение одного расчетного периода. Типичный пример из сферы ЖКХ — изменение тарифа на электроэнергию или воду в середине месяца. Если мы используем стандартный механизм СрезПоследних, система вернет нам только одно, самое актуальное значение на указанную дату. Но как быть, если нам нужно увидеть и «старый», и «новый» тариф, чтобы корректно рассчитать сумму? Рассмотрим решение этой задачи, разобрав ошибки и выбрав правильные инструменты запросов.

В чем заключается проблема Среза последних?

Для начала проанализируем, как работает виртуальная таблица СрезПоследних. Когда мы обращаемся к ней, платформа выполняет сложный расчет «на лету»: для каждой уникальной комбинации измерений она ищет запись с максимальной датой (периодом), которая меньше или равна дате среза. Результатом всегда будет только одна строка для каждого набора измерений.

В ситуации с коммунальными платежами, если тариф сменился 15-го числа, а мы делаем срез на 30-е число, система покажет только тариф, действующий с 15-го числа. Данные о том, что первые две недели действовала другая цена, будут «отрезаны». Чтобы обойти это ограничение, нам необходимо сменить подход и обратиться к первоисточнику данных.

Решение №1: Использование физической таблицы регистра

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

Разберем, как построить запрос к физической таблице для получения всех изменений за месяц. Рассмотрим пример на основе регистра НачисленияПоКонтрагентам_Извещения:


ВЫБРАТЬ
    Начисления.Период КАК ДатаИзменения,
    Начисления.Контрагент КАК Контрагент,
    Начисления.Номенклатура КАК Услуга,
    Начисления.Цена КАК Цена,
    Начисления.ОбъектНедвижимости КАК Объект
ИЗ
    РегистрСведений.НачисленияПоКонтрагентам_Извещения КАК Начисления
ГДЕ
    Начисления.Период МЕЖДУ &НачалоМесяца И &КонецМесяца
    И Начисления.Контрагент = &Контрагент

Этот запрос вернет нам столько строк, сколько раз менялась цена в указанном диапазоне дат. Если цена менялась 1-го и 15-го числа, мы получим обе записи. Это именно то, что нужно для вывода нескольких «платежек» или строк в одной квитанции.

Решение №2: Получение «предыдущего» значения (срез на разные даты)

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

Рассмотрим пошагово алгоритм получения данных:

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

Однако этот метод сложен в реализации, если у разных контрагентов цены менялись в разные дни. В таком случае лучше использовать соединение физической таблицы самой с собой для поиска предыдущего периода. Проанализируем пример такого запроса:


ВЫБРАТЬ
    Т1.Период КАК ТекущийПериод,
    МАКСИМУМ(Т2.Период) КАК ПредыдущийПериод
ПОМЕСТИТЬ ВТ_Периоды
ИЗ
    РегистрСведений.Цены КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены КАК Т2
    ПО Т1.Номенклатура = Т2.Номенклатура
    И Т1.Период > Т2.Период
СГРУППИРОВАТЬ ПО
    Т1.Период

Здесь мы находим для каждой записи самую близкую к ней дату «из прошлого». Это позволяет выстроить цепочку изменений цен для каждого объекта учета.

Решение №3: Комплексный запрос для ЖКХ (тарифы + показания)

В реальных задачах нам часто нужно соединить данные из двух разных регистров: Цены (или Начисления) и ПоказанияСчетчиков. Важно помнить, что соединять их нужно не только по объекту недвижимости или прибору учета, но и по времени.

Выясним, как правильно собрать данные для печатной формы, если нам нужны и начисления, и разница показаний приборов учета. Посмотрим на структуру запроса с использованием временных таблиц:


// Помещаем данные о начислениях во временную таблицу
ВЫБРАТЬ
    Начисления.Контрагент,
    Начисления.Цена,
    Начисления.ПриборУчета,
    Начисления.Период
ПОМЕСТИТЬ ВТ_Начисления
ИЗ
    РегистрСведений.НачисленияПоКонтрагентам_Извещения КАК Начисления
ГДЕ
    Начисления.Период МЕЖДУ &НачалоМесяца И &КонецМесяца;

////////////////////////////////////////////////////////////////////////////////
// Помещаем показания счетчиков (срез последних на дату документа)
ВЫБРАТЬ
    Показания.ПриборУчета,
    Показания.Показание КАК ТекущееПоказание,
    Показания.РазницаПоказаний
ПОМЕСТИТЬ ВТ_Показания
ИЗ
    РегистрСведений.ПоказанияСчетчиковОбъектовНедвижимости.СрезПоследних(&Период) КАК Показания;

////////////////////////////////////////////////////////////////////////////////
// Соединяем данные
ВЫБРАТЬ
    ВТ_Начисления.Контрагент,
    ВТ_Начисления.Цена КАК Тариф,
    ВТ_Показания.ТекущееПоказание,
    ВТ_Показания.РазницаПоказаний
ИЗ
    ВТ_Начисления КАК ВТ_Начисления
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Показания КАК ВТ_Показания
    ПО ВТ_Начисления.ПриборУчета = ВТ_Показания.ПриборУчета
ИТОГИ ПО
    ВТ_Начисления.Контрагент

Важные рекомендации при работе с физическими таблицами

При переходе от виртуальных таблиц к физическим следует учитывать несколько критически важных моментов:

Таким образом, если ваша задача — показать динамику изменения данных или вывести все тарифы, действовавшие внутри месяца, забудьте про СрезПоследних. Используйте прямую выборку из регистра с жестким фильтром по датам и измерениям. Это обеспечит и точность данных, и гибкость формирования печатных форм.

← На главную