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