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