Как сгруппировать данные регистра по физлицу и получить общий период в одну строку?

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

При разработке отчетов на платформе 1С часто возникает задача собрать разрозненные записи регистра в одну сводную строку. Рассмотрим типичную ситуацию: есть регистр накопления Проживание, в котором хранятся данные о заездах физических лиц. По одному человеку может быть несколько записей с разными периодами (например, с 23.06 по 25.06, с 26.06 по 28.06 и с 29.06 по 05.07). Цель — вывести в отчет всего одну строку по этому человеку, где датой заезда будет самое начало проживания (23.06), а датой выезда — самый конец (05.07). Разберем по шагам, как правильно решить эту задачу, какие ошибки часто допускаются и как оформить результат в Системе Компоновки Данных (СКД).

Анализ исходной ошибки: почему запрос выдает несколько строк

Проанализируем ситуацию, с которой столкнулся разработчик. Изначально для решения задачи использовалась конструкция ВЫБРАТЬ РАЗЛИЧНЫЕ, а также сложный выбор колонок. Посмотрим на логику работы оператора РАЗЛИЧНЫЕ. Он оставляет только уникальные комбинации всех выбранных полей. Так как даты начала и окончания в каждой строке регистра разные, платформа справедливо считает эти строки уникальными и выводит все три записи в результат.

Позже разработчик попытался применить оператор СГРУППИРОВАТЬ ПО, но допустил распространенную ошибку, включив в группировку сами даты:


ВЫБРАТЬ 
    МИНИМУМ(Проживание.ПериодНачала) КАК ПериодНачала, 
    МАКСИМУМ(Проживание.ПериодОкончания) КАК ПериодОкончания, 
    Проживание.Физлицо КАК Физлицо, 
    Проживание.КолвоДней КАК КолвоДней 
ИЗ 
    РегистрНакопления.Проживание КАК Проживание 
ГДЕ 
    Проживание.Период МЕЖДУ &ДатаЗаезда1 И &ДатаЗаезда2 
СГРУППИРОВАТЬ ПО 
    Проживание.Физлицо, 
    Проживание.ПериодНачала, 
    Проживание.ПериодОкончания, 
    Проживание.КолвоДней

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

Правильное решение: группировка и агрегатные функции

Выясним причину и применим правильный подход. Чтобы свернуть данные до одной строки в разрезе физического лица, нам необходимо оставить в секции СГРУППИРОВАТЬ ПО исключительно поле Физлицо (и другие справочные поля, если они нужны, например, ФИО или телефон). Все остальные числовые поля или даты должны обрабатываться агрегатными функциями.

Для дат начала мы используем МИНИМУМ, чтобы найти самый ранний заезд, а для дат окончания — МАКСИМУМ, чтобы зафиксировать последний выезд. Количество дней логично суммировать с помощью СУММА. Рассмотрим исправленный вариант запроса:


ВЫБРАТЬ 
    МИНИМУМ(Проживание.ПериодНачала) КАК ПериодНачала, 
    МАКСИМУМ(Проживание.ПериодОкончания) КАК ПериодОкончания, 
    СУММА(Проживание.КолвоДней) КАК КолвоДней,
    Проживание.Физлицо КАК Физлицо 
ИЗ 
    РегистрНакопления.Проживание КАК Проживание 
ГДЕ 
    Проживание.Период МЕЖДУ &ДатаЗаезда1 И &ДатаЗаезда2 
СГРУППИРОВАТЬ ПО 
    Проживание.Физлицо

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

Почему не стоит использовать виртуальную таблицу "Обороты"?

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

Разберем детально: поле Физлицо в конфигурации автора является реквизитом регистра, а не его измерением. Архитектура платформы 1С устроена таким образом, что виртуальные таблицы (Обороты, Остатки) строятся исключительно в разрезе измерений регистра. Реквизиты служат для хранения дополнительной справочной информации к конкретному движению и в механизм автоматической агрегации не попадают. Следовательно, обратившись к таблице оборотов, мы просто не найдем там поля Физлицо.

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

Проблема прерываний в периодах (Gaps and Islands)

Рассмотрим еще один критически важный аспект логики. В нашем решении мы берем абсолютный минимум и максимум дат. Но что делать, если в проживании были перерывы? Например, гость жил с 1 по 5 число, затем уехал, и вернулся с 15 по 20 число. Применив МИНИМУМ и МАКСИМУМ, мы получим один период с 1 по 20 число. Система "склеит" даты, и мы посчитаем, что человек проживал непрерывно 20 дней, хотя по факту он отсутствовал 10 дней.

В нашем конкретном случае автор уточнил, что прерывания исключены. Однако, если бы прерывания допускались, задача перешла бы в разряд классической проблемы объединения пересекающихся или смежных интервалов (известной как Gaps and Islands). В 1С она решается двумя основными путями:

  1. Сложным запросом. Моменты времени собираются в одну временную таблицу. Запрос вычисляет "элементарные" неделимые интервалы, а затем с помощью соединения таблиц проверяет условия вхождения дат одна в другую, объединяя только те периоды, которые идут стык в стык или пересекаются.
  2. Программной постобработкой. Результат запроса выгружается в объект ТаблицаЗначений и сортируется по дате начала. Далее с помощью простого цикла перебираются строки: если дата начала следующей строки меньше или равна дате окончания текущей строки, интервалы сливаются путем обновления даты окончания. Если больше — начинается новый независимый интервал.

Оформление отчета: настройка заголовков в СКД

После получения корректных данных часто возникает проблема оформления, в частности — установки понятных заголовков колонок в отчете. Платформа 1С через Систему Компоновки Данных предоставляет несколько гибких инструментов для решения этой задачи. Рассмотрим три способа настройки:

  1. Через настройки СКД (пользовательский режим). Это самый простой путь. В схеме СКД перейдите на вкладку "Настройки", выберите группировку или весь отчет, перейдите на вкладку "Выбранные поля". Нажмите правой кнопкой мыши на нужное поле (например, ПериодНачала), выберите пункт "Установить заголовок" и впишите желаемый текст (например, "Дата заезда"). Этот заголовок переопределит синоним поля из исходного запроса.
  2. Использование пользовательских макетов. Если нужно сложное оформление шапки (например, объединение ячеек или добавление параметров), перейдите на вкладку "Макеты" в СКД. Добавьте "Макет заголовка группировки". В свойствах ячеек табличного документа установите тип заполнения "Шаблон". Это позволит писать текст с динамическими вставками, например: Данные по проживанию с [ПериодНачала] по [ПериодОкончания]. Платформа автоматически подставит значения.
  3. Программное изменение заголовков. Если настройки должны меняться динамически в зависимости от условий (например, от выбранного пользователем режима отчета), используется обработчик события ПриКомпоновкеРезультата в модуле объекта отчета. В нем можно программно обратиться к коллекции пользовательских настроек компоновщика и подменить заголовки полей до того, как система сгенерирует финальный табличный документ.

Подводя итог, можно сказать, что работа с физическими таблицами регистров накопления требует четкого понимания принципов группировки в SQL-запросах 1С. Важно отличать измерения от реквизитов при использовании виртуальных таблиц, всегда учитывать бизнес-логику (наличие возможных прерываний) и эффективно использовать визуальные инструменты СКД для финализации отчета.

← На главную