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