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