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