Как выбрать один штрихкод для номенклатуры в запросе 1С, если их несколько?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки печатных форм, таких как счет на оплату или расходная накладная, программисты часто сталкиваются с ситуацией, когда для одной позиции номенклатуры в базе данных зарегистрировано несколько штрихкодов. Это может быть связано с наличием разных упаковок, характеристик или просто историческим накоплением кодов (например, EAN-13 и внутренний код предприятия). Однако на печать необходимо вывести только одно значение.

В этой статье мы разберем, почему стандартные попытки ограничить выборку могут не работать, и рассмотрим эффективные способы решения этой задачи с помощью механизмов запросов 1С и программного кода.

Анализ проблемы: почему не работает ВЫБРАТЬ ПЕРВЫЕ 1 в условии ГДЕ

Рассмотрим типичную ошибку начинающих разработчиков. Часто пытаются использовать конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 внутри подзапроса в секции ГДЕ. Проблема заключается в том, что условие Штрихкод В (ВЫБРАТЬ ПЕРВЫЕ 1...) без жесткой корреляции подзапроса с основным запросом просто проверяет наличие штрихкода в некоем списке из одного элемента. Если основной запрос выбирает все штрихкоды номенклатуры, а подзапрос возвращает «какой-то один» из всей таблицы, то условие сработает некорректно для всего набора строк документа.

Чтобы получить ровно одну строку штрихкода для каждой строки номенклатуры в отчете или печатной форме, необходимо использовать механизмы группировки или коррелированные соединения.

Способ 1: Использование агрегатных функций в запросе

Это наиболее эффективный метод, когда нам нужно получить список товаров вместе со штрихкодами одним пакетом данных. Суть метода заключается в «схлопывании» нескольких записей регистра сведений до одной с помощью функции МАКСИМУМ или МИНИМУМ.

Проанализируем пример запроса, который позволяет выбрать по одному штрихкоду для каждой позиции из документа ЗаказКлиента:


ВЫБРАТЬ
    ЗаказТовары.Номенклатура КАК Номенклатура,
    ВложенныйЗапрос.Штрихкод КАК Штрихкод,
    ЗаказТовары.Количество КАК Количество,
    ЗаказТовары.Сумма КАК Сумма
ИЗ
    Документ.ЗаказКлиента.Товары КАК ЗаказТовары
        ЛЕВОЕ СОЕДИНЕНИЕ (
            ВЫБРАТЬ
                МАКСИМУМ(РегистрШтрихкоды.Штрихкод) КАК Штрихкод,
                РегистрШтрихкоды.Номенклатура КАК Номенклатура
            ИЗ
                РегистрСведений.ШтрихкодыНоменклатуры КАК РегистрШтрихкоды
            СГРУППИРОВАТЬ ПО
                РегистрШтрихкоды.Номенклатура
        ) КАК ВложенныйЗапрос
        ПО ЗаказТовары.Номенклатура = ВложенныйЗапрос.Номенклатура
ГДЕ
    ЗаказТовары.Ссылка = &Ссылка

Разберем по шагам, что происходит в этом запросе:

  1. Мы обращаемся к табличной части документа (например, ЗаказКлиента.Товары).
  2. Создаем вложенный запрос к регистру сведений ШтрихкодыНоменклатуры.
  3. Во вложенном запросе используем СГРУППИРОВАТЬ ПО полю Номенклатура. Это гарантирует, что для каждого владельца будет возвращена только одна строка.
  4. С помощью функции МАКСИМУМ(Штрихкод) мы выбираем один из доступных кодов. Обычно это код, который является наибольшим по алфавиту (или числовому значению, если штрихкод хранится как число).
  5. Соединяем основную таблицу товаров с этим вложенным запросом по полю Номенклатура.

Важный момент: Если в вашей конфигурации штрихкоды ведутся в разрезе характеристик или упаковок, обязательно добавьте эти поля в условия соединения ПО и в секцию СГРУППИРОВАТЬ ПО вложенного запроса. В противном случае вы можете получить штрихкод, который не соответствует конкретной единице измерения или свойству товара.

Способ 2: Программное получение штрихкода в цикле

Если вам не нужно формировать сложный отчет, а требуется получить штрихкод для конкретной строки при выводе печатной формы в цикле, можно использовать отдельную функцию. Этот метод проще в отладке и позволяет более гибко настраивать фильтрацию.

Рассмотрим пример функции, которая возвращает структуру с данными штрихкода:


Функция ПолучитьШтрихкодДляНоменклатуры(Владелец, Упаковка = Неопределено, Характеристика = Неопределено)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |    Штрихкоды.ТипШтрихкода,
    |    Штрихкоды.Штрихкод
    |ИЗ
    |    РегистрСведений.Штрихкоды КАК Штрихкоды
    |ГДЕ
    |    Штрихкоды.Владелец = &Владелец
    |    И Штрихкоды.Упаковка = &Упаковка
    |    И Штрихкоды.Характеристика = &Характеристика";
    
    Запрос.УстановитьПараметр("Владелец", Владелец);
    Запрос.УстановитьПараметр("Упаковка", ?(Упаковка = Неопределено, Справочники.УпаковкиНоменклатуры.ПустаяСсылка(), Упаковка));
    Запрос.УстановитьПараметр("Характеристика", ?(Характеристика = Неопределено, Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка(), Характеристика));
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Штрихкод;
    КонецЕсли;
    
    Возврат "";
КонецФункции

В данном случае использование ВЫБРАТЬ ПЕРВЫЕ 1 абсолютно оправдано, так как запрос выполняется для конкретного объекта. Мы ограничиваем выборку одной записью, что исключает дублирование строк в печатной форме.

Рекомендации по оптимизации и качеству данных

Выясним причину, по которой данных может быть много, и как сделать выбор более осознанным. Просто взять МАКСИМУМ — это техническое решение, но не всегда бизнес-логически верное.

Приоритет типов штрихкодов
Часто на предприятии используются и внутренние коды (например, начинающиеся на "20"), и международные EAN-13. Если вы хотите, чтобы в счете всегда выводился именно EAN-13, в запрос стоит добавить условие фильтрации по полю ТипШтрихкода. Если же типов может быть несколько, можно использовать конструкцию ВЫБОР в запросе, чтобы присвоить разным типам веса (приоритеты) и выбирать код с наивысшим приоритетом.

Использование временных таблиц
Для повышения производительности, особенно в крупных базах, рекомендуем сначала отобрать уникальный список номенклатуры из документа во временную таблицу, а затем соединять эту временную таблицу с регистром штрихкодов. Это избавит СУБД от необходимости сканировать весь регистр или группировать лишние данные.

Проверка единиц измерения
Обратите внимание на условие из исходного вопроса автора: Штрихкоды.ЕдиницаИзмерения.ЕдиницаПоКлассификатору = Штрихкоды.Владелец.БазоваяЕдиницаИзмерения. Это очень важное уточнение. Штрихкод для штуки и штрихкод для коробки (упаковки) — это разные сущности. Всегда проверяйте, что единица измерения штрихкода совпадает с единицей измерения, указанной в строке документа, иначе клиент может получить счет со штрихкодом целой паллеты вместо одного изделия.

Таким образом, для гарантированного получения одного штрихкода в 1С используйте либо группировку с агрегатными функциями (в сложных запросах), либо ограничение выборки ПЕРВЫЕ 1 (при точечном получении данных).

← На главную