Как правильно заполнить колонку штрихкодов в таблице значений из регистра сведений?

Программист Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ исходной проблемы

Разберем ситуацию: у нас есть ТаблицаСерий (объект ТаблицаЗначений), в которой уже присутствуют колонки Номенклатура и ХарактеристикаНоменклатуры. Нам необходимо добавить колонку Штрихкод и заполнить ее данными из регистра сведений Штрихкоды.

Наивный подход заключается в том, чтобы в цикле по каждой строке таблицы искать данные в регистре или предварительно выгрузить весь регистр в память и использовать метод НайтиСтроки(). Однако, если в таблице сотни строк, а в регистре — десятки тысяч, производительность системы упадет до критического уровня. Проанализируем, как сделать это правильно.

Метод №1: Использование запроса с передачей таблицы значений в качестве параметра

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

Шаг 1. Подготовка и типизация таблицы

Чтобы запрос смог обработать ТаблицаЗначений, ее колонки должны иметь строго определенные типы. Если таблица создана динамически без указания типов, запрос выдаст ошибку. Подготовим типизированную копию нашей таблицы:


// Создаем новую таблицу с типизированными колонками
ТС = Новый ТаблицаЗначений;
ТС.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТС.Колонки.Добавить("ХарактеристикаНоменклатуры", Новый ОписаниеТипов("СправочникСсылка.ХарактеристикиНоменклатуры"));

// Копируем данные из исходной ТаблицаСерий
Для Каждого СтрокаИзИсходной Из ТаблицаСерий Цикл
    ЗаполнитьЗначенияСвойств(ТС.Добавить(), СтрокаИзИсходной);
КонецЦикла;

Использование ЗаполнитьЗначенияСвойств позволяет быстро перенести данные в новую структуру, не обращаясь к каждой колонке по имени вручную.

Шаг 2. Выполнение запроса с левым соединением

Теперь передадим подготовленную таблицу в запрос. Мы используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы сохранить все строки исходной таблицы, даже если для какой-то номенклатуры штрихкод в базе не найден.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВТ_Исходная.Номенклатура КАК Номенклатура,
    |	ВТ_Исходная.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры
    |ПОМЕСТИТЬ ПромТаблица
    |ИЗ
    |	&ТЗ КАК ВТ_Исходная
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	ПромТаблица.Номенклатура,
    |	ПромТаблица.ХарактеристикаНоменклатуры,
    |	ЕСТЬNULL(РегистрШтрихкоды.Штрихкод, """") КАК Штрихкод
    |ИЗ
    |	ПромТаблица КАК ПромТаблица
    |		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Штрихкоды КАК РегистрШтрихкоды
    |		ПО ПромТаблица.Номенклатура = РегистрШтрихкоды.Владелец
    |			И ПромТаблица.ХарактеристикаНоменклатуры = РегистрШтрихкоды.ХарактеристикаНоменклатуры";

Запрос.УстановитьПараметр("ТЗ", ТС);
РезультатЗапроса = Запрос.Выполнить();
ТаблицаСоШтрихкодами = РезультатЗапроса.Выгрузить();

Важный нюанс: Обратите внимание на функцию ЕСТЬNULL(..., ""). Она гарантирует, что если штрихкод не найден, в колонку запишется пустая строка, а не значение NULL, которое может вызвать ошибки при дальнейшей программной обработке.

Метод №2: Использование объекта «Соответствие» (Map)

Если по каким-то причинам использование временных таблиц в запросе нежелательно (например, в очень специфических внешних обработках), можно применить метод сопоставления через Соответствие. Это работает быстрее, чем НайтиСтроки() в цикле.

Разберем алгоритм:

  1. Выгружаем уникальный список номенклатуры из нашей таблицы.
  2. Одним запросом получаем все штрихкоды для этих позиций.
  3. Заполняем объект Соответствие, где ключом будет уникальный идентификатор (или комбинация полей), а значением — штрихкод.
  4. Проходим циклом по исходной таблице и быстро подставляем данные.

// 1. Получаем список уникальных владельцев
СписокНом = ТаблицаСерий.ВыгрузитьКолонку("Номенклатура");

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

// 3. Заполняем соответствие
КэшШтрихкодов = Новый Соответствие;
Пока Выборка.Следующий() Цикл
    // Создаем ключ из Номенклатуры и Характеристики
    Ключ = Строка(Выборка.Владелец.УникальныйИдентификатор()) + "_" + Строка(Выборка.ХарактеристикаНоменклатуры.УникальныйИдентификатор());
    КэшШтрихкодов.Вставить(Ключ, Выборка.Штрихкод);
КонецЦикла;

// 4. Заполняем основную таблицу
Для Каждого Стр Из ТаблицаСерий Цикл
    КлючПоиска = Строка(Стр.Номенклатура.УникальныйИдентификатор()) + "_" + Строка(Стр.ХарактеристикаНоменклатуры.УникальныйИдентификатор());
    НайденныйШтрихкод = КэшШтрихкодов.Получить(КлючПоиска);
    Стр.Штрихкод = ?(НайденныйШтрихкод = Неопределено, "", НайденныйШтрихкод);
КонецЦикла;

Сравнение и рекомендации

Проанализируем оба метода. Метод с запросом (№1) является эталонным. Он минимизирует количество передаваемых данных между сервером приложений и сервером СУБД. Вся тяжелая работа по сопоставлению строк выполняется на стороне SQL-сервера, который оптимизирован для таких задач.

Метод с соответствием (№2) полезен, когда нужно выполнить сложную логику проверки на стороне 1С, которую трудно описать в языке запросов. Однако он потребляет больше оперативной памяти на сервере приложений.

Рассмотрим важные советы по оптимизации:

Выясним причину частых ошибок: многие начинающие разработчики пытаются использовать ТаблицаЗначений.НайтиСтроки() внутри цикла. Помните, что каждый вызов этого метода заставляет систему просматривать таблицу, что при вложенном цикле превращает сложность алгоритма в квадратичную. Использование временных таблиц в запросе переводит решение в разряд линейных и профессиональных.

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

← На главную