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