Разработка и Конфигурация · 12 мин
Как сравнить две табличные части в 1С
Способы сравнения двух табличных частей в 1С: перебор строк, таблицы значений, свёртка и запросы. Примеры кода, типичные ошибки и проверка результата.
Задача сравнения двух табличных частей в 1С возникает постоянно: нужно определить, изменил ли пользователь табличную часть документа, найти расхождения между товарами заказа и реализации, сверить данные до и после обработки. Универсальной кнопки «сравнить» в платформе нет, поэтому разработчик выбирает один из нескольких рабочих подходов в зависимости от объёма данных и того, что именно считается различием.
Ключевой момент, который нужно определить до написания кода, — критерий сравнения. Иногда достаточно совпадения количества строк и итоговых сумм, иногда требуется построчное совпадение по всем колонкам, а иногда важен порядок строк. От этого зависит и алгоритм, и производительность решения.
Ниже разобраны четыре практических способа: прямой перебор строк, сравнение через таблицы значений, свёртка с контролем итогов и сравнение запросом. Для каждого приведены условия применимости, пример кода и типичные ошибки.
Что определить перед написанием кода
Прежде чем выбирать алгоритм, ответьте на три вопроса. Первый: сравниваются табличные части одного объекта (например, до и после изменения) или разных документов. Второй: важен ли порядок строк — для товарных документов он обычно не важен, а для этапов производственной операции может быть критичен. Третий: какие колонки участвуют в сравнении — все или только ключевые (номенклатура, количество, сумма).
Отдельно проверьте типы данных в колонках. Если в одной таблице количество хранится как Число(15,3), а в другой — как Число(15,2), построчное сравнение может дать ложные расхождения из-за округления. То же относится к строковым полям с разной длиной и к ссылкам на разные, но логически эквивалентные элементы справочника.
Для одного объекта достаточно копии табличной части в памяти, для разных нужны две выгрузки
Если не важен — применяйте свёртку, если важен — только попарный перебор по индексу
Сравнение по всем колонкам строже, но чувствительно к служебным полям
При больших объёмах перебор в цикле заметно медленнее запроса
Способ 1. Попарный перебор строк по индексу
Самый простой вариант, когда табличные части должны совпадать полностью, включая порядок строк. Сначала сравнивается количество строк, затем в цикле проверяется каждая пара строк по нужным колонкам. Этот способ удобен для проверки «изменилась ли табличная часть» в событиях ПередЗаписью или ПриКопировании.
Функция ТабличныеЧастиРавны(ТЧ1, ТЧ2)
Если ТЧ1.Количество() <> ТЧ2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для Индекс = 0 По ТЧ1.Количество() - 1 Цикл
Строка1 = ТЧ1[Индекс];
Строка2 = ТЧ2[Индекс];
Если Строка1.Номенклатура <> Строка2.Номенклатура
Или Строка1.Количество <> Строка2.Количество
Или Строка1.Сумма <> Строка2.Сумма Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Ограничение способа очевидно: если пользователь просто поменял строки местами, сравнение покажет различие, хотя по смыслу табличные части одинаковы. Также при большом числе колонок перечислять их в условии утомительно и легко забыть новую колонку после доработки конфигурации.
Способ 2. Сравнение через таблицы значений и свёртку
Универсальный приём, когда порядок строк не важен. Обе табличные части выгружаются в таблицы значений, во второй таблице количественные показатели меняют знак на противоположный, затем таблицы объединяются и сворачиваются по ключевым колонкам. Строки, где после свёртки количество или сумма не равны нулю, — это и есть расхождения.
ТЗ1 = ТабличнаяЧасть1.Выгрузить();
ТЗ2 = ТабличнаяЧасть2.Выгрузить();
Для Каждого Строка Из ТЗ2 Цикл
Строка.Количество = -Строка.Количество;
Строка.Сумма = -Строка.Сумма;
КонецЦикла;
Для Каждого Строка Из ТЗ2 Цикл
НоваяСтрока = ТЗ1.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЦикла;
ТЗ1.Свернуть("Номенклатура", "Количество,Сумма");
Для Каждого Строка Из ТЗ1 Цикл
Если Строка.Количество <> 0 Или Строка.Сумма <> 0 Тогда
// Расхождение по этой номенклатуре
КонецЕсли;
КонецЦикла;
Этот подход хорош тем, что сразу показывает не только факт расхождения, но и его величину: положительный остаток означает избыток в первой таблице, отрицательный — во второй. Метод широко используется для сверки товарных документов, например заказа и реализации.
Учтите ограничение: свёртка работает корректно только по числовым колонкам. Если нужно сравнить строковые поля (например, серию или содержание услуги), включите их в перечень колонок группировки, а не суммирования — тогда строки с разными значениями не схлопнутся.
Перед свёрткой убедитесь, что обе таблицы имеют одинаковый состав колонок, иначе при копировании строк возникнет ошибка или значения потеряются. Надёжнее выгружать обе табличные части с явным списком колонок: Выгрузить(,"Номенклатура,Количество,Сумма").
Способ 3. Сравнение запросом
Когда табличные части содержат сотни или тысячи строк, сравнение запросом работает заметно быстрее цикла, потому что вся обработка выполняется на уровне СУБД. Обе таблицы передаются в запрос как параметры, помещаются во временные таблицы и соединяются полным соединением по ключевым полям.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ТЗ1", ТабличнаяЧасть1.Выгрузить());
Запрос.УстановитьПараметр("ТЗ2", ТабличнаяЧасть2.Выгрузить());
Запрос.Текст =
"ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма
|ПОМЕСТИТЬ ВТ1 ИЗ &ТЗ1 КАК Т
|;
|ВЫБРАТЬ Т.Номенклатура, Т.Количество, Т.Сумма
|ПОМЕСТИТЬ ВТ2 ИЗ &ТЗ2 КАК Т
|;
|ВЫБРАТЬ
| ЕСТЬNULL(ВТ1.Номенклатура, ВТ2.Номенклатура) КАК Номенклатура,
| ЕСТЬNULL(ВТ1.Количество, 0) - ЕСТЬNULL(ВТ2.Количество, 0) КАК РазницаКоличество,
| ЕСТЬNULL(ВТ1.Сумма, 0) - ЕСТЬNULL(ВТ2.Сумма, 0) КАК РазницаСумма
|ИЗ ВТ1 КАК ВТ1
| ПОЛНОЕ СОЕДИНЕНИЕ ВТ2 КАК ВТ2
| ПО ВТ1.Номенклатура = ВТ2.Номенклатура
|ГДЕ
| ЕСТЬNULL(ВТ1.Количество, 0) <> ЕСТЬNULL(ВТ2.Количество, 0)
| ИЛИ ЕСТЬNULL(ВТ1.Сумма, 0) <> ЕСТЬNULL(ВТ2.Сумма, 0)";
Результат запроса содержит только расходящиеся строки. Пустой результат означает полное совпадение. Полное соединение гарантирует, что будут найдены и строки, отсутствующие в первой таблице, и строки, отсутствующие во второй.
Обратите внимание: если по одной номенклатуре в табличной части может быть несколько строк, перед запросом выгрузите и сверните таблицы, иначе соединение перемножит строки и разница посчитается неверно. Также помните, что передача таблицы значений параметром требует, чтобы все её колонки имели типы, допустимые в запросе.
Способ 4. Быстрая проверка через итоги и хеш
Если нужно не найти расхождения, а только ответить на вопрос «одинаковые ли таблицы», достаточно лёгкой проверки. Простейший вариант — сравнить количество строк и итоги по числовым колонкам методом Итог(): ТЧ1.Итог("Сумма") <> ТЧ2.Итог("Сумма"). Это мгновенная проверка, которая отсеивает большинство различий, хотя теоретически может пропустить взаимокомпенсирующие изменения.
Более строгий вариант — сериализовать выгрузку в строку (например, через ЗначениеВСтрокуВнутр или формирование XML) и сравнить полученные строки или их хеши. Такой подход удобен для журналирования: вместо хранения копии табличной части сохраняется только хеш, и изменение любой строки мгновенно обнаруживается.
Сравнение способов
Подходит для проверки полного совпадения с учётом порядка строк; не находит перестановки и медленен на больших объёмах
Оптимален для сверки товаров и сумм без учёта порядка; показывает величину расхождения, но требует одинаковой структуры колонок
Лучший выбор для больших таблиц и выборочного сравнения; требует аккуратности с дублями ключевых строк
Самое быстрое для ответа «изменилось или нет»; не показывает, где именно расхождение
Как проверить результат сравнения
После внедрения любого из способов проверьте его на контрольных примерах. Создайте пару идентичных табличных частей — результат должен быть «равно». Затем измените одну строку, добавьте строку, удалите строку и поменяйте две строки местами: убедитесь, что алгоритм реагирует именно так, как задумано, а перестановка либо игнорируется, либо фиксируется — в зависимости от требований.
Для способа со свёрткой полезно вывести строки с ненулевым остатком в сообщение или табличный документ: это позволяет пользователю сразу увидеть, по какой номенклатуре и на какую сумму расхождение, вместо сухого «таблицы не совпадают».
Как проверить результат
Результат сравнения — совпадение, список расхождений пуст
Найдены различия — проверьте типы колонок и округление
Поведение соответствует требованию (игнорируется или фиксируется)
Свёртка фиксирует перестановку — значит, в группировку попала лишняя колонка
Расхождение в пределах заданной точности не фиксируется
Ложные расхождения на копейки — добавьте округление перед сравнением
Типичные ошибки при сравнении табличных частей
Чаще всего проблемы возникают не из-за алгоритма, а из-за подготовки данных. Разные типы колонок, служебные поля, попавшие в сравнение, и неучтённые дубли ключевых строк дают ложные расхождения или, наоборот, маскируют реальные различия.
Отдельная ошибка — сравнение табличной части из формы с данными объекта в базе без учёта модифицированности. Пользователь мог изменить строки, но не записать документ; запрос к базе в этот момент вернёт старые данные, и сравнение будет некорректным.
Что важно запомнить
Сначала определите критерий сравнения: порядок строк, состав колонок, допустимая точность чисел. Для сверки без учёта порядка используйте выгрузку и свёртку с инверсией знака, для больших объёмов — запрос с полным соединением, для проверки факта изменения — итоги или хеш. Всегда проверяйте алгоритм на контрольных примерах и работайте с реальными документами через копию базы.
Частые вопросы
Как сравнить табличные части двух разных документов?
Выгрузите обе табличные части в таблицы значений с одинаковым списком колонок и примените свёртку с инверсией знака или запрос с полным соединением. Ссылки на сами документы в сравнение включать не нужно — сравниваются только содержательные колонки: номенклатура, количество, цена, сумма.
Можно ли сравнить табличные части без программирования?
Штатной команды сравнения табличных частей в типовых конфигурациях обычно нет. Варианты без кода: вывести обе табличные части в табличный документ и сравнить визуально, либо использовать универсальные отчёты и консоль сравнения данных, если они есть в вашей конфигурации. Для регулярной сверки всё же потребуется небольшая обработка.
Как учесть порядок строк при сравнении?
Только попарным перебором по индексу: свёртка и запрос порядок не сохраняют. Если порядок важен, но таблицы большие, добавьте в выгрузку колонку с номером строки и включите её в условия соединения запроса.
Почему свёртка показывает расхождение, хотя таблицы визуально одинаковые?
Наиболее вероятные причины: разные типы или точность числовых колонок, лишние пробелы в строковых полях, разные ссылки при одинаковом наименовании (например, дубли номенклатуры). Выгрузите обе таблицы и сравните значения проблемной строки по каждой колонке отдельно.
Как сравнить табличную часть до и после изменения пользователем?
При открытии формы или в начале редактирования сохраните копию выгрузки табличной части в реквизит формы или переменную модуля. При записи или закрытии сравните текущую табличную часть с сохранённой копией любым из описанных способов — для этого сценария обычно достаточно попарного перебора или сравнения итогов.
Что делать, если табличные части содержат тысячи строк и сравнение тормозит?
Откажитесь от вложенных циклов поиска строк — это квадратичная сложность. Используйте запрос с полным соединением или метод НайтиСтроки с соответствием-индексом: постройте соответствие, где ключ — строка из значений ключевых колонок, и проверяйте наличие каждой строки за одно обращение.