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