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