Был у меня как-то клиент, разрабатывали ему конфигурацию по управлению сетью хостелов.
И вот возникла одна несложная задачка: сделать отчет, который будет показывать состояние комнат на какой-то момент времени в следующем виде:
Группировка по Хостелам и комнатам, детали: проживающий, дата заезда, планируемая дата выезда и что-то там еще по проживающим:
…
Комната 313 (5 мест)
Иванов Иван Перович, 01.01.2016, 31.01.2016
Пупкин Петр Васильевич, 05.01.2016, 25.01.2016
СВОБОДНО
СВОБОДНО
СВОБОДНО
Самое интересное и оказалось в том, что каждое свободное место в комнате должно выводиться отдельной строчкой.
Структура конфигурации не предполагала учет по конкретным местам и более того, нигде, кроме этого отчета и не возникала такая необходимость. Т.е. у нас есть информация о количестве мест в комнате всего и о каждом проживающим, каждый из которых занимает 1 место.
Конечно, можно было бы быстренько состряпать отдельный отчет и сделать так:
Для i 1 по КоличествоСободныхМест Цикл
ТабДок.Вывести("ОбластьСвободноеМесто");
КонецЦикла;
Но как только я давным давно познакомился С КД, я старался делать все отчеты с помощью компоновки. Причина в двух неоспоримых плюсах: быстрота разработки и гибкость настроек для пользователя. В 99% случаев я даже формы не создавал для отчетов, все прекрасно описывается в схеме компоновки. И псевдонимы полей, и списки значений, а если надо – можно пользоваться функциями общих модулей. В общем очень не хотел я делать шаг в прошлое, поэтому достаточно быстро в голове родился вариант решения. Томить не стану, вот оно само решение, набросал без метаданных, чтобы любой желающий смог быстро посмотреть его в консоли:
В
ВЫБРАТЬ 0 КАК Число
ПОМЕСТИТЬ ВТ_До10
ОБЪЕДИНИТЬ
ВЫБРАТЬ 1
ОБЪЕДИНИТЬ
ВЫБРАТЬ 2
ОБЪЕДИНИТЬ
ВЫБРАТЬ 3
ОБЪЕДИНИТЬ
ВЫБРАТЬ 4
ОБЪЕДИНИТЬ
ВЫБРАТЬ 5
ОБЪЕДИНИТЬ
ВЫБРАТЬ 6
ОБЪЕДИНИТЬ
ВЫБРАТЬ 7
ОБЪЕДИНИТЬ
ВЫБРАТЬ 8
ОБЪЕДИНИТЬ
ВЫБРАТЬ 9
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_До10.Число * 10 + ВТ_До10_1.Число КАК Индекс
ПОМЕСТИТЬ ВТ_ПустыеСтроки
ИЗ
ВТ_До10 КАК ВТ_До10,
ВТ_До10 КАК ВТ_До10_1
//Повторить сколько угодно раз, ориентируясь на максимально возможный индекс
ГДЕ
ВТ_До10.Число * 10 + ВТ_До10_1.Число > 0
;
////////////////////////////////////////////////////////////////////////////////
//Тестовые данные - Комнаты
ВЫБРАТЬ
"Комната1" КАК Комната,
5 КАК КоличествоМест
ПОМЕСТИТЬ ВТ_Комнаты
ОБЪЕДИНИТЬ
ВЫБРАТЬ
"Комната2",
4
;
////////////////////////////////////////////////////////////////////////////////
//Тестовые данные - состояние проживающих
ВЫБРАТЬ
"Комната1" КАК Комната,
"Иванов Иван Иванович" КАК Постоялец,
ДАТАВРЕМЯ(2016, 1, 1, 0, 0, 0) КАК ДатаЗаезда,
ДАТАВРЕМЯ(2016, 1, 31, 0, 0, 0) КАК ПланируемаяДатаВыезда
ПОМЕСТИТЬ ВТ_ИнфорамцияОПроживающих
ОБЪЕДИНИТЬ
ВЫБРАТЬ
"Комната1",
"Пупкин Петр Васильевич",
ДАТАВРЕМЯ(2016, 1, 5, 0, 0, 0),
ДАТАВРЕМЯ(2016, 1, 25, 0, 0, 0)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ИнфорамцияОПроживающих.Комната,
ВТ_ИнфорамцияОПроживающих.Постоялец,
ВТ_ИнфорамцияОПроживающих.ДатаЗаезда,
ВТ_ИнфорамцияОПроживающих.ПланируемаяДатаВыезда
ИЗ
ВТ_ИнфорамцияОПроживающих КАК ВТ_ИнфорамцияОПроживающих
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СвободныеМеста.Комната,
"СВОБОДНО",
NULL,
NULL
ИЗ
(ВЫБРАТЬ
ВТ_Комнаты.Комната КАК Комната,
ВТ_Комнаты.КоличествоМест - ЕСТЬNULL(КОЛИЧЕСТВО(ВТ_ИнфорамцияОПроживающих.Постоялец), 0) КАК СвободноМест
ИЗ
ВТ_Комнаты КАК ВТ_Комнаты
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИнфорамцияОПроживающих КАК ВТ_ИнфорамцияОПроживающих
ПО ВТ_Комнаты.Комната = ВТ_ИнфорамцияОПроживающих.Комната
СГРУППИРОВАТЬ ПО
ВТ_Комнаты.Комната,
ВТ_Комнаты.КоличествоМест) КАК СвободныеМеста
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ПустыеСтроки КАК ВТ_ПустыеСтроки
ПО СвободныеМеста.СвободноМест >= ВТ_ПустыеСтроки.Индекс
В принципе, данный способ можно использовать везде, где есть необходимость что-то учесть в запросе X раз, именно не умножить на X, а сделать X строк из одной.