В практике разработки на платформе 1С:Предприятие часто встречается задача, когда результат запроса возвращает данные в «вертикальном» виде (множество строк), а пользователю необходимо представить их в «горизонтальном» (одна строка с множеством колонок). Классический пример — отображение характеристик номенклатуры. В базе данных характеристики хранятся в отдельных записях, но в интерфейсе обработки или документа мы хотим видеть одну строку с товаром и несколько колонок для его свойств: «Характеристика 1», «Характеристика 2» и так далее.
Рассмотрим подробно, как решить эту задачу, имея фиксированную структуру табличной части (например, заранее созданные колонки «Характеристика1», «Характеристика2», «Характеристика3»). Мы разберем несколько методов: от классического обхода группировок до манипуляций с Таблицей Значений.
Допустим, у нас есть результат запроса, который выглядит следующим образом:
Нам необходимо загрузить эти данные в табличную часть обработки, которая имеет структуру:
Номенклатура | Характеристика 1 | Характеристика 2 | Характеристика 3
В итоге должно получиться:
Это наиболее производительный и правильный с точки зрения архитектуры 1С метод. Суть заключается в том, что мы перекладываем работу по группировке данных на SQL-сервер (или движок файловой базы), используя конструкцию ИТОГИ (вам может пригодиться Шпаргалка по языку запросов). Затем мы используем двойной цикл обхода выборки.
Разберем алгоритм по шагам:
ИТОГИ ПО Номенклатура. Это позволит нам получать данные порциями: сначала заголовок (Товар), затем детальные записи (Характеристики). Используйте инструменты для быстрого анализа данных, чтобы проверить корректность работы итогов.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам).Рассмотрим пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладах.Номенклатура КАК Номенклатура,
| ТоварыНаСкладах.Характеристика КАК Характеристика
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
|
|УПОРЯДОЧИТЬ ПО
| Номенклатура,
| Характеристика
|ИТОГИ ПО
| Номенклатура";
// Получаем результат запроса
Результат = Запрос.Выполнить();
// Начинаем выборку по группировкам (по Номенклатуре)
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаНоменклатура.Следующий() Цикл
// Для каждой новой номенклатуры создаем новую строку в табличной части
НоваяСтрока = Объект.МояТабличнаяЧасть.Добавить();
НоваяСтрока.Номенклатура = ВыборкаНоменклатура.Номенклатура;
// Получаем детальные записи (характеристики) для текущей номенклатуры
ВыборкаДетали = ВыборкаНоменклатура.Выбрать();
Счетчик = 1; // Сбрасываем счетчик для новой строки
Пока ВыборкаДетали.Следующий() Цикл
// Проверяем, чтобы не выйти за пределы созданных колонок (например, если их всего 3)
Если Счетчик > 3 Тогда
Прервать;
КонецЕсли;
// Формируем имя колонки динамически: "Характеристика" + "1", "2" и т.д.
ИмяКолонки = "Характеристика" + Строка(Счетчик);
// Записываем значение в колонку
НоваяСтрока[ИмяКолонки] = ВыборкаДетали.Характеристика;
// Увеличиваем счетчик для следующей характеристики
Счетчик = Счетчик + 1;
КонецЦикла;
КонецЦикла;
Проверить текст запроса и структуру итогов удобнее всего через Консоль запросов УФ 8.3.2.24.22 (мод от Dr.Zombi). Преимущества метода:
Если вы по каким-то причинам не хотите использовать итоги в запросе или уже имеете плоскую таблицу значений с данными, можно использовать алгоритм свертки и поиска строк. Этот метод менее эффективен на больших объемах данных, так как требует многократного поиска, но он интуитивно понятен.
Алгоритм действий:
Номенклатура. Так мы получим список уникальных товаров (будущих строк ТЧ).Посмотрим на реализацию:
// Допустим, Запрос уже выполнен и выгружен в ТЗ
ТЗ_ВсеДанные = Запрос.Выполнить().Выгрузить();
// Создаем таблицу уникальных номенклатур
ТЗ_Уникальные = ТЗ_ВсеДанные.Скопировать();
ТЗ_Уникальные.Свернуть("Номенклатура"); // Останутся только уникальные товары
Для Каждого СтрУник Из ТЗ_Уникальные Цикл
// Добавляем строку в табличную часть
НоваяСтрокаТЧ = Объект.МояТабличнаяЧасть.Добавить();
НоваяСтрокаТЧ.Номенклатура = СтрУник.Номенклатура;
// Ищем все строки с этой номенклатурой в исходной таблице
Отбор = Новый Структура("Номенклатура", СтрУник.Номенклатура);
НайденныеСтроки = ТЗ_ВсеДанные.НайтиСтроки(Отбор);
Счетчик = 1;
Для Каждого СтрДетали Из НайденныеСтроки Цикл
Если Счетчик > 3 Тогда
Прервать;
КонецЕсли;
НоваяСтрокаТЧ["Характеристика" + Строка(Счетчик)] = СтрДетали.Характеристика;
Счетчик = Счетчик + 1;
КонецЦикла;
КонецЦикла;
Этот метод удобен, если данные уже находятся в памяти в виде ТаблицаЗначений, например, полученные из внешней системы или другого документа.
Если ваша задача — просто вывести список характеристик для информации (в одну ячейку), и вы используете современную платформу версии 8.3.24 и выше, можно воспользоваться новой функцией языка запросов АгрегатСтроки (StringAggregate).
Это не разнесет данные по разным колонкам, но позволит собрать их в одну строку через запятую прямо в запросе, что часто заменяет необходимость создания множества колонок.
ВЫБРАТЬ
Товары.Номенклатура,
АгрегатСтроки(Товары.Характеристика, ", ") КАК ВсеХарактеристики
ИЗ
Справочник.Товары КАК Товары
СГРУППИРОВАТЬ ПО
Товары.Номенклатура
Результатом будет одна строка: «Размер XL, Цвет Красный». Если же строго требуется разделение по колонкам для дальнейшего редактирования, используйте Способ 1.
Ограничение количества колонок. В приведенных примерах мы жестко ограничивали цикл условием Если Счетчик > 3. Это необходимо, так как в метаданных (в Конфигураторе) у вас создано конечное количество реквизитов (Характеристика1, Характеристика2, Характеристика3). Если характеристик будет 4, и вы попытаетесь обратиться к НоваяСтрока["Характеристика4"], платформа выдаст ошибку, так как такого поля не существует.
Динамические колонки. Если вы заранее не знаете, сколько будет характеристик (может быть 3, а может быть 10), то фиксированная табличная часть вам не подойдет. В этом случае необходимо использовать программное создание реквизитов формы. Алгоритм будет сложнее:
ИзменитьРеквизиты программно добавить нужное количество колонок в ТаблицаЗначений на форме.Элементы.Добавить создать поля ввода для этих колонок в таблице формы.Однако для большинства типовых задач по заполнению документов достаточно подхода с фиксированным количеством столбцов и использованием итогов в запросе.