При формировании печатных форм часто возникает задача компактного размещения информации: вместо одного длинного вертикального списка необходимо вывести данные в две параллельные колонки (например, слева строки с 1 по 10, а справа — с 11 по 20). При реализации такого алгоритма разработчики нередко сталкиваются с ошибками типизации и неправильной работой с объектами выборки. Разберем по шагам, почему возникают эти ошибки и какими способами можно правильно вывести данные в две колонки.
Рассмотрим, с какими трудностями чаще всего сталкиваются при попытке разделить данные на две части непосредственно в процессе обхода выборки:
КолВо = ВыборкаДетальныеЗаписи.КолВоСтр;, написанный до первого вызова ВыборкаДетальныеЗаписи.Следующий(), возвращает значение Неопределено. Позиционирование на первой записи происходит только после выполнения метода Следующий(). При попытке выполнить математическую операцию (например, деление на 2) система выдает исключение: «Преобразование значения к типу Число не может быть выполнено».КОЛИЧЕСТВО(...) с группировкой по всем полям возвращает единицу для каждой отдельной строки, а не общее количество строк в выборке. Общее число записей выборки следует получать встроенной функцией ВыборкаДетальныеЗаписи.Количество().ВыборкаИзРезультатаЗапроса является однонаправленным курсором. По нему нельзя произвольно переходить по индексам назад или «перепрыгивать» в середину списка, чтобы параллельно читать первую и вторую половины выборки.Наиболее надежный и простой способ сформировать две колонки сверху вниз — выгрузить результат запроса в объект ТаблицаЗначений. Это позволяет мгновенно узнать общее количество строк и обращаться к произвольным строкам по их числовому индексу.
Разберем по шагам логику расчета:
РезультатЗапроса.Выгрузить().Цел((ВсегоСтрок + 1) / 2).НомерСтроки, а для правой — со смещением НомерСтроки + ВысотаТаблицы.Посмотрим на пример реализации данного алгоритма:
ТаблицаСертификатов = РезультатЗапроса.Выгрузить();
ВсегоСтрок = ТаблицаСертификатов.Количество();
Если ВсегоСтрок > 0 Тогда
ВысотаТаблицы = Цел((ВсегоСтрок + 1) / 2);
ОбластьШапка = Макет.ПолучитьОбласть("ШапкаСертификаты");
ТабДок.Вывести(ОбластьШапка);
ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаСертификаты");
Для НомерСтроки = 0 По ВысотаТаблицы - 1 Цикл
// Заполняем левую колонку
СтрокаЛево = ТаблицаСертификатов[НомерСтроки];
ОбластьСтрока.Параметры.СертификатыКод = СтрокаЛево.Код;
ОбластьСтрока.Параметры.СертификатыНаименование = СтрокаЛево.Номенклатура;
// Заполняем правую колонку, проверяя наличие элемента
ИндексПраво = НомерСтроки + ВысотаТаблицы;
Если ИндексПраво < ВсегоСтрок Тогда
СтрокаПраво = ТаблицаСертификатов[ИндексПраво];
ОбластьСтрока.Параметры.СертификатыКод2 = СтрокаПраво.Код;
ОбластьСтрока.Параметры.СертификатыНаименование2 = СтрокаПраво.Номенклатура;
Иначе
ОбластьСтрока.Параметры.СертификатыКод2 = "";
ОбластьСтрока.Параметры.СертификатыНаименование2 = "";
КонецЕсли;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
КонецЕсли;
Если бизнес-логика допускает заполнение таблицы слева направо (1-я запись слева, 2-я запись справа, 3-я слева и т. д.), можно обойтись без промежуточной выгрузки в память и обойти выборку напрямую.
Рассмотрим реализацию пошагового обхода:
Выборка = РезультатЗапроса.Выбрать();
ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаСертификаты");
Пока Выборка.Следующий() Цикл
// Заполняем левую часть строки
ОбластьСтрока.Параметры.СертификатыКод = Выборка.Код;
ОбластьСтрока.Параметры.СертификатыНаименование = Выборка.Номенклатура;
// Пытаемся получить данные для правой части
Если Выборка.Следующий() Тогда
ОбластьСтрока.Параметры.СертификатыКод2 = Выборка.Код;
ОбластьСтрока.Параметры.СертификатыНаименование2 = Выборка.Номенклатура;
Иначе
ОбластьСтрока.Параметры.СертификатыКод2 = "";
ОбластьСтрока.Параметры.СертификатыНаименование2 = "";
КонецЕсли;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Проанализируем ситуацию, когда макет разделен на две отдельные вертикальные области: ОбластьЛево и ОбластьПраво. При использовании метода Присоединить() табличного документа важно помнить: он добавляет колонки строго вправо от текущей последней выведенной строки.
Разберем пример правильного вывода с параллельным присоединением:
ТаблицаДанных = РезультатЗапроса.Выгрузить();
Всего = ТаблицаДанных.Количество();
ВысотаТаблицы = Цел((Всего + 1) / 2);
ОбластьЛево = Макет.ПолучитьОбласть("КолонкаЛево");
ОбластьПраво = Макет.ПолучитьОбласть("КолонкаПраво");
Для Стр = 0 По ВысотаТаблицы - 1 Цикл
// Выводим левую ячейку вниз
ОбластьЛево.Параметры.Заполнить(ТаблицаДанных[Стр]);
ТабДок.Вывести(ОбластьЛево);
// Присоединяем правую ячейку в ту же строку справа
ИндексПраво = Стр + ВысотаТаблицы;
Если ИндексПраво < Всего Тогда
ОбластьПраво.Параметры.Заполнить(ТаблицаДанных[ИндексПраво]);
ТабДок.Присоединить(ОбластьПраво);
КонецЕсли;
КонецЦикла;
Таким образом, для разделения данных на две половины оптимальным решением является выгрузка в ТаблицуЗначений с индексным доступом, так как она дает полный контроль над позиционированием элементов и корректно обрабатывает нечетное число строк.