Как программно найти документы с одинаковым составом табличной части в 1С?

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

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

Метод 1: Сравнение через временные таблицы и количество строк

Этот метод считается наиболее надежным с точки зрения логики БД. Мы проанализируем состав документов, используя внутренние соединения, и проверим два критерия: полное совпадение номенклатуры и равенство общего количества строк. Рассмотрим алгоритм реализации через запрос:

  1. Выбираем уникальные строки из табличных частей обоих типов документов.
  2. Группируем данные, чтобы получить количество строк для каждого документа.
  3. Соединяем таблицы по ключевым полям (например, Номенклатура и Количество).
  4. Отсекаем те пары, у которых количество совпавших строк не равно общему количеству строк в документе.

Разберем пример кода запроса, который позволяет сопоставить Заказы и Реализации:


ВЫБРАТЬ
    ОбщиеСтроки.Заказ КАК Заказ,
    ОбщиеСтроки.Реализация КАК Реализация
ИЗ
    (ВЫБРАТЬ
        Заказы.Ссылка КАК Заказ,
        Реализации.Ссылка КАК Реализация,
        КОЛИЧЕСТВО(*) КАК ОбщихСтрок
    ИЗ
        Документ.ЗаказПокупателя.Товары КАК Заказы
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
        Документ.РеализацияТоваровУслуг.Товары КАК Реализации
    ПО 
        Заказы.Номенклатура = Реализации.Номенклатура
        И Заказы.Количество = Реализации.Количество
    СГРУППИРОВАТЬ ПО
        Заказы.Ссылка,
        Реализации.Ссылка) КАК ОбщиеСтроки
ГДЕ
    ОбщиеСтроки.ОбщихСтрок = (ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ Документ.ЗаказПокупателя.Товары ГДЕ Ссылка = ОбщиеСтроки.Заказ)
    И ОбщиеСтроки.ОбщихСтрок = (ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ Документ.РеализацияТоваровУслуг.Товары ГДЕ Ссылка = ОбщиеСтроки.Реализация)

Важный нюанс: если в документе одна и та же номенклатура может встречаться в нескольких строках, данные перед сравнением необходимо предварительно свернуть во временной таблице. В противном случае простое сравнение по количеству строк выдаст неверный результат.

Метод 2: Высокопроизводительное хеширование в запросе

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

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


ВЫБРАТЬ
    Товары.Ссылка КАК Ссылка,
    СУММА(
        923521 * ВЫБОР ПОДСТРОКА(Товары.Номенклатура.Код, 1, 1) КОГДА "0" ТОГДА 1 КОГДА "1" ТОГДА 2 ИНАЧЕ 0 КОНЕЦ +
        28629151 * ВЫБОР ПОДСТРОКА(Товары.Номенклатура.Код, 2, 1) КОГДА "0" ТОГДА 1 КОГДА "1" ТОГДА 2 ИНАЧЕ 0 КОНЕЦ
    ) КАК Хэш
ПОМЕСТИТЬ ВТ_Хеши
ИЗ
    Документ.ЗаказПокупателя.Товары КАК Товары
СГРУППИРОВАТЬ ПО
    Товары.Ссылка;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Хеши.Ссылка,
    ВТ_Хеши.Хэш
ИЗ
    ВТ_Хеши КАК ВТ_Хеши
ИТОГИ ПО
    ВТ_Хеши.Хэш

Проанализируем этот подход: использование СУММА позволяет игнорировать порядок строк в документе (так как от перемены мест слагаемых сумма не меняется), что критически важно при сравнении табличных частей. Однако помните, что равенство хешей не гарантирует 100% равенства данных (возможны коллизии), поэтому найденные «подозрительные» документы стоит проверить финальным точным сравнением.

Метод 3: Оптимизация через Регистр Сведений

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

Рассмотрим шаги реализации:

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

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

Метод 4: Программное сравнение через соответствие (Map)

Иногда задачу нужно решить «здесь и сейчас» в коде на языке 1С без написания сложных запросов. В этом случае мы можем использовать объект Соответствие для быстрого поиска.

Выясним причину выбора этого метода: работа с объектом Соответствие в памяти происходит быстрее, чем вложенные циклы. Мы можем использовать хеш-строку состава в качестве ключа.


Функция ПолучитьКлючСостава(ДокументСсылка)
    ТЗ = ДокументСсылка.Товары.Выгрузить();
    ТЗ.Сортировать("Номенклатура");
    Ключ = "";
    Для Каждого Стр Из ТЗ Цикл
        Ключ = Ключ + "_" + Стр.Номенклатура.УникальныйИдентификатор() + ":" + Стр.Количество;
    КонецЦикла;
    Возврат Ключ;
КонецФункции

// Пример использования:
ХешиДокументов = Новый Соответствие;
// ... обход выборки документов
Ключ = ПолучитьКлючСостава(ТекДокумент);
Если ХешиДокументов[Ключ] <> Неопределено Тогда
    Сообщить("Найден дубль состава: " + ТекДокумент + " и " + ХешиДокументов[Ключ]);
Иначе
    ХешиДокументов.Вставить(Ключ, ТекДокумент);
КонецЕсли;

Важный совет: при формировании строки-ключа всегда используйте УникальныйИдентификатор ссылки, а не наименование, так как наименования могут дублироваться или содержать спецсимволы, ломающие логику сравнения.

Подведение итогов

Выбор метода зависит от ваших приоритетов:

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

← На главную