Как в запросе 1С получить данные по всей иерархии (номер, комната, койка) для отображения в Диаграмме Ганта

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

При разработке систем бронирования или учета проживания часто возникает задача визуализации занятости номерного фонда. Типичная структура данных в таких задачах представляет собой цепочку подчиненных справочников: Номер (как объект размещения) содержит Комнаты, а комнаты содержат Койки (конкретные спальные места). Основная сложность заключается в том, чтобы не просто вытянуть детальные записи о заселении, но и корректно "поднять" эти данные на уровни выше для построения иерархического дерева в ДиаграммеГанта.

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

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

Рассмотрим стандартную ситуацию: у нас есть справочник Койки, который подчинен справочнику Комнаты, а тот, в свою очередь, подчинен справочнику Номера. Чтобы получить всю цепочку в запросе, разработчики часто используют обращение через точку от поля Владелец.

Проанализируем типичный запрос, который на первый взгляд кажется верным:


ВЫБРАТЬ
    Койки.Владелец.Владелец.Ссылка КАК Номер,
    Койки.Владелец.Ссылка КАК Комната,
    Койки.Ссылка КАК Койка,
    ЗагруженностьНФ.ДатаЗаселения КАК ДатаЗаселения,
    ЗагруженностьНФ.ДатаВыезда КАК ДатаВыезда
ИЗ
    Справочник.Койки КАК Койки
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗагруженностьНФ КАК ЗагруженностьНФ
    ПО Койки.Ссылка = ЗагруженностьНФ.КойкаПроживания
УПОРЯДОЧИТЬ ПО
    Комната,
    Койка
ИТОГИ ПО
    Номер,
    Комната,
    Койка

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

Совет: Всегда пишите просто Койки.Владелец вместо Койки.Владелец.Ссылка. Это делает код чище и быстрее.

Проблема пустых уровней иерархии

Выясним причину, по которой некоторые записи могут не попадать в результат. Если вы используете ЛЕВОЕ СОЕДИНЕНИЕ от справочника Койки к регистру сведений, вы увидите только те данные, которые привязаны к конкретным койкам. Если в вашей системе есть записи о загрузке, созданные на уровне "Комнаты" целиком (например, бронирование всего номера без указания коек), они будут отсечены.

Если данные есть в регистре, но их нет у владельца, проверьте следующие моменты:

  1. Заполнение владельца: Убедитесь, что у каждой койки в базе заполнен реквизит Владелец. Если владелец пуст, обращение Койки.Владелец.Владелец вернет NULL, и такая запись "схлопнется" в итогах.
  2. Тип соединения: Если вам важно видеть все записи о загрузке, даже те, у которых нет привязки к справочнику Койки, стоит рассмотреть ПОЛНОЕ СОЕДИНЕНИЕ или строить запрос от регистра сведений, присоединяя к нему справочники.

Работа с итогами и агрегатными функциями

Рассмотрим ситуацию, когда при обходе результата запроса в коде 1С вы обнаруживаете, что на уровне "Комната" или "Номер" даты заселения равны NULL, хотя в детальных записях (на уровне коек) они заполнены. Это происходит потому, что в секции ИТОГИ не указаны агрегатные функции для ресурсов.

Посмотрим, как должен выглядеть профессионально составленный запрос для ДиаграммыГанта:


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

Добавление МАКСИМУМ(ДатаЗаселения) позволяет системе "поднять" значения дат на верхние уровни группировки. Теперь при обращении к ВыборкаКомната.ДатаЗаселения вы получите не пустое значение, а крайнюю дату из всех вложенных коек.

Программное заполнение Диаграммы Ганта

После того как мы оптимизировали запрос, перейдем к заполнению визуального компонента. Разберем по шагам логику обхода выборок. Важно помнить, что в ДиаграммеГанта мы работаем с объектами Точка и их интервалами.

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


РезультатЗапроса = Запрос.Выполнить();
ВыборкаНомер = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаНомер.Следующий() Цикл
    // Создаем верхний уровень в диаграмме
    ТочкаНомер = ДиаграммаГанта.УстановитьТочку(ВыборкаНомер.Номер);
    
    ВыборкаКомната = ВыборкаНомер.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока ВыборкаКомната.Следующий() Цикл
        // Добавляем подчиненную точку
        ТочкаКомната = ТочкаНомер.Точки.Добавить();
        ТочкаКомната.Значение = ВыборкаКомната.Комната;
        ТочкаКомната.Текст = Строка(ВыборкаКомната.Комната);

        ВыборкаКойка = ВыборкаКомната.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
        Пока ВыборкаКойка.Следующий() Цикл
            ТочкаКойка = ТочкаКомната.Точки.Добавить();
            ТочкаКойка.Значение = ВыборкаКойка.Койка;
            
            // Теперь работаем с детальными записями для получения интервалов
            ВыборкаДетальные = ВыборкаКойка.Выбрать();
            Пока ВыборкаДетальные.Следующий() Цикл
                Если ВыборкаДетальные.ДатаЗаселения <> NULL Тогда
                    // Добавляем интервал на уровень КОЙКИ
                    ЗначениеКойка = ДиаграммаГанта.ПолучитьЗначение(ТочкаКойка, Серия);
                    Интервал = ЗначениеКойка.Добавить();
                    Интервал.Начало = ВыборкаДетальные.ДатаЗаселения;
                    Интервал.Конец = ВыборкаДетальные.ДатаВыезда;
                    
                    // Если нужно, чтобы полоска отображалась и на уровне комнаты:
                    ЗначениеКомната = ДиаграммаГанта.ПолучитьЗначение(ТочкаКомната, Серия);
                    ИнтервалК = ЗначениеКомната.Добавить();
                    ИнтервалК.Начало = ВыборкаДетальные.ДатаЗаселения;
                    ИнтервалК.Конец = ВыборкаДетальные.ДатаВыезда;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
КонецЦикла;

Почему данные могут "пропадать" в циклах?

Выясним причину частой ошибки: использование условия Если ВыборкаКомната.ДатаЗаселения <> NULL внутри цикла по группировкам без использования итоговых функций. Если в запросе не было МАКСИМУМ(ДатаЗаселения), то на уровне группировки "Комната" это поле всегда будет NULL, даже если данные в базе есть. Программа просто не зайдет внутрь условия и не добавит интервалы на диаграмму.

Важные моменты при работе с иерархией:

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

← На главную