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