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

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

Сравнение табличных частей — это классическая задача, с которой сталкивается каждый разработчик 1С (поможет инструментарий администратора 1С для анализа и сравнения данных). Казалось бы, что может быть проще: сравнить две таблицы. Однако на практике возникает множество нюансов: нужно ли учитывать порядок строк? Как быть с дублями? Как обеспечить высокую производительность на больших объемах данных? В этой статье мы подробно разберем основные методики сравнения, проанализируем их плюсы и минусы, а также выберем наиболее оптимальные подходы для различных ситуаций.

Метод 1. Использование запроса (универсальный и точный способ)

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

Проанализируем пример запроса, который находит расхождения между двумя источниками данных:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Источник.Номенклатура КАК Номенклатура,
    |	Источник.Характеристика КАК Характеристика,
    |	СУММА(Источник.Количество) КАК Количество
    |ПОМЕСТИТЬ ВТ_Источник
    |ИЗ
    |	&ТЗ_Источник КАК Источник
    |СГРУППИРОВАТЬ ПО
    |	Источник.Номенклатура,
    |	Источник.Характеристика
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	Приемник.Номенклатура КАК Номенклатура,
    |	Приемник.Характеристика КАК Характеристика,
    |	СУММА(Приемник.Количество) КАК Количество
    |ПОМЕСТИТЬ ВТ_Приемник
    |ИЗ
    |	&ТЗ_Приемник КАК Приемник
    |СГРУППИРОВАТЬ ПО
    |	Приемник.Номенклатура,
    |	Приемник.Характеристика
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	ЕСТЬNULL(ВТ_Источник.Номенклатура, ВТ_Приемник.Номенклатура) КАК Номенклатура,
    |	ЕСТЬNULL(ВТ_Источник.Характеристика, ВТ_Приемник.Характеристика) КАК Характеристика,
    |	ЕСТЬNULL(ВТ_Источник.Количество, 0) КАК КоличествоИст,
    |	ЕСТЬNULL(ВТ_Приемник.Количество, 0) КАК КоличествоПрм
    |ИЗ
    |	ВТ_Источник КАК ВТ_Источник
    |		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Приемник КАК ВТ_Приемник
    |		ПО ВТ_Источник.Номенклатура = ВТ_Приемник.Номенклатура
    |			И ВТ_Источник.Характеристика = ВТ_Приемник.Характеристика
    |ГДЕ
    |	ЕСТЬNULL(ВТ_Источник.Количество, 0) <> ЕСТЬNULL(ВТ_Приемник.Количество, 0)";

Запрос.УстановитьПараметр("ТЗ_Источник", ТаблицаИсточника);
Запрос.УстановитьПараметр("ТЗ_Приемник", ТаблицаПриемника);

Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
    // Таблицы различаются
    Выборка = Результат.Выбрать();
    Пока Выборка.Следующий() Цикл
        // Обработка конкретных расхождений
    КонецЦикла;
КонецЕсли;

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

Метод 2. Типовые функции БСП

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

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

Пример использования:


Если ОбщегоНазначения.ТаблицыЗначенийСовпадают(Таблица1, Таблица2) Тогда
    Сообщить("Таблицы абсолютно идентичны");
Иначе
    Сообщить("В таблицах есть различия");
КонецЕсли;

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

Метод 3. Сравнение перебором с индексацией

Бывают случаи, когда использование запроса избыточно (например, на клиенте в управляемых формах), а БСП недоступна. Тогда мы прибегаем к ручному сравнению в цикле. Однако помните: простой перебор одной таблицы и поиск в другой через НайтиСтроки() работает крайне медленно на больших объемах (сложность O(n*m)).

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


// Подготовим таблицы
ТаблицаИсточник.Сортировать("Номенклатура, Характеристика");
ТаблицаПриемник.Сортировать("Номенклатура, Характеристика");

// Добавляем индекс для ускорения поиска
ТаблицаИсточник.Индексы.Добавить("Номенклатура, Характеристика");

Если ТаблицаИсточник.Количество() <> ТаблицаПриемник.Количество() Тогда
    Возврат Ложь; // Разное количество строк - таблицы уже не равны
КонецЕсли;

Для Каждого СтрокаПрм Из ТаблицаПриемник Цикл
    Отбор = Новый Структура("Номенклатура, Характеристика", СтрокаПрм.Номенклатура, СтрокаПрм.Характеристика);
    НайденныеСтроки = ТаблицаИсточник.НайтиСтроки(Отбор);
    
    Если НайденныеСтроки.Количество() = 0 Тогда
        Сообщить("Строка не найдена!");
        Прервать;
    ИначеЕсли НайденныеСтроки[0].Количество <> СтрокаПрм.Количество Тогда
        Сообщить("Количество отличается!");
        Прервать;
    КонецЕсли;
КонецЦикла;

Использование Индексы.Добавить позволяет методу НайтиСтроки работать практически мгновенно, превращая медленный перебор в эффективную операцию.

Метод 4. Сериализация в XML или JSON

Иногда требуется максимально простой код для быстрой проверки "на лету". Один из нестандартных, но работающих способов — превратить таблицы в строки (сериализовать) и сравнить эти строки между собой. Мы можем использовать СериализаторXDTO или ЗаписьJSON.

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


// Сортировка обязательна для этого метода!
ТЗ1.Сортировать("Номенклатура");
ТЗ2.Сортировать("Номенклатура");

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, ТЗ1);
Строка1 = Запись.Закрыть();

Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, ТЗ2);
Строка2 = Запись.Закрыть();

Если Строка1 = Строка2 Тогда
    // Таблицы идентичны
КонецЕсли;

Распространенные ошибки при сравнении

  1. Сравнение только по количеству строк: Как справедливо заметили участники форума, если в одной таблице "банан, хлеб", а в другой "хлеб, хлеб", количество строк совпадет (2), но данные будут разными.
  2. Использование объекта СравнениеЗначений: Нужно четко понимать, что СравнениеЗначений.Сравнить(ТЗ1, ТЗ2) в 1С не выполняет построчное сравнение содержимого таблиц. Он лишь сравнивает ссылки на объекты в памяти или типы данных. Для коллекций этот метод бесполезен.
  3. Забытая сортировка: Любой метод, кроме агрегирующего запроса, требует одинакового порядка строк. Без сортировки вы получите ложноотрицательный результат (данные одинаковые, но порядок разный — результат "Не равны").
  4. Дубли строк: Если в табличной части одна и та же номенклатура введена двумя строками, обычный поиск найдет только первую. В таких случаях перед сравнением данные лучше сгруппировать (схлопнуть) — для этого подойдёт обработка поиска и устранения дублей объектов в 1С.

Рекомендации по выбору метода

Подведем итог нашему анализу и выберем лучший инструмент под конкретную задачу:

Рассмотрев все эти варианты, мы видим, что правильный выбор метода зависит от объема данных и доступных инструментов в вашей конфигурации. Тщательно анализируйте структуру своих данных перед выбором алгоритма, и ваше решение будет работать быстро и безошибочно.

← На главную