В процессе интеграции 1С с внешними сервисами через API часто возникает ситуация, когда мы получаем список конкретных экземпляров продукции (уникальные идентификаторы exemplars_id), но соответствующие им коды маркировки (DataMatrix) хранятся в нашей базе без привязки к этим ID — только в связке с общим product_id. Проанализируем, как можно «подружить» эти таблицы и корректно распределить марки между экземплярами, чтобы избежать дублей и ошибок в учете.
Представим, что у нас есть две таблицы. Первая таблица содержит перечень экземпляров, полученных извне. В ней есть product_id (общий код товара) и exemplars_id (уникальный серийный номер или идентификатор упаковки). Поле marka в этой таблице пустое, и его нужно заполнить.
Вторая таблица — это наш внутренний список свободных марок для этого product_id. Главная сложность заключается в том, что маркировка в базе «не знает» о существовании exemplars_id из API. Нам нужно распределить их по принципу «одна марка на один экземпляр».
Этот метод считается наиболее надежным и простым в реализации, особенно если данные от API приходят в виде объектов, а не хранятся в базе данных. Рассмотрим алгоритм действий:
ТаблицаЗначений.product_id.product_id найдем подходящую строку во второй таблице.Разберем пример кода, реализующий эту логику:
// Допустим, ТЗ_Экземпляры и ТЗ_Марки уже заполнены
Для Каждого СтрокаЭкземпляра Из ТЗ_Экземпляры Цикл
ПараметрыОтбора = Новый Структура("product_id", СтрокаЭкземпляра.product_id);
НайденныеМарки = ТЗ_Марки.НайтиСтроки(ПараметрыОтбора);
Если НайденныеМарки.Количество() > 0 Тогда
// Берем первую доступную марку
ТекущаяМарка = НайденныеМарки[0];
СтрокаЭкземпляра.marka = ТекущаяМарка.marka;
// Удаляем использованную марку из пула доступных
ТЗ_Марки.Удалить(ТекущаяМарка);
КонецЕсли;
КонецЦикла;
Преимущество этого метода: мы на 100% гарантируем уникальность распределения. Даже если данные в API дублируются, программный метод исключит повторное использование одного и того же кода маркировки.
Рассмотрим ситуацию, когда мы хотим решить задачу исключительно средствами языка запросов 1С. Поскольку в 1С нет встроенной функции ROW_NUMBER(), нам придется имитировать её. Основная идея заключается в том, чтобы пронумеровать строки внутри каждой группы product_id в обеих таблицах, а затем соединить их по двум полям: product_id и ПорядковыйНомер.
Проанализируем шаги построения такого запроса:
exemplars_id или marka).Т1.product_id = Т2.product_id И Т1.exemplars_id >= Т2.exemplars_id. Сгруппировав по Т1.exemplars_id и рассчитав Количество(Т2.exemplars_id), мы получим порядковый номер.ЛЕВОЕ СОЕДИНЕНИЕ первой таблицы со второй по полям product_id и НомерСтроки.Посмотрим на пример структуры запроса для нумерации:
ВЫБРАТЬ
Т1.product_id,
Т1.exemplars_id,
КОЛИЧЕСТВО(Т2.exemplars_id) КАК ПорядковыйНомер
ПОМЕСТИТЬ ВТ_ЭкземплярыСНомером
ИЗ
ВТ_Экземпляры КАК Т1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Экземпляры КАК Т2
ПО Т1.product_id = Т2.product_id
И Т1.exemplars_id >= Т2.exemplars_id
СГРУППИРОВАТЬ ПО
Т1.product_id,
Т1.exemplars_id
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Т_Связь.product_id,
Т_Связь.exemplars_id,
ВТ_МаркиСНомером.marka
ИЗ
ВТ_ЭкземплярыСНомером КАК Т_Связь
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_МаркиСНомером КАК ВТ_МаркиСНомером
ПО Т_Связь.product_id = ВТ_МаркиСНомером.product_id
И Т_Связь.ПорядковыйНомер = ВТ_МаркиСНомером.ПорядковыйНомер
Важное ограничение: этот метод эффективен только на небольших выборках. При больших объемах данных (тысячи строк) соединение «каждой строки с каждой» внутри группы приведет к резкому падению производительности запроса.
Выясним причину, по которой простое распределение «любая марка к любому ID» может быть опасным. Если результат этого сопоставления не записывается в базу данных (например, в РегистрСведений), то при повторном формировании запроса или отчета порядок марок может измениться. Это создаст «кашу» в учете, когда один и тот же экземпляр в разных документах будет фигурировать с разными кодами маркировки.
Чтобы избежать подобных проблем, рекомендуем придерживаться следующих правил:
exemplars_id + marka в специально созданный регистр сведений.ЛЕВОЕ СОЕДИНЕНИЕ), и только если марки там нет — запускайте механизм распределения новых свободных кодов.Мы рассмотрели два основных способа решения задачи. Если вы работаете с небольшими объемами данных, приходящими из API в реальном времени, выбирайте программный обход Таблицы Значений — это проще в отладке и гарантирует отсутствие ошибок дублирования. Если же вам необходимо обработать огромный массив данных, уже хранящийся в базе, используйте запрос с имитацией ROW_NUMBER(), но помните о нагрузке на сервер.
Для долгосрочной стабильности системы всегда фиксируйте результат сопоставления в базе данных, чтобы обеспечить прослеживаемость каждой единицы товара.