К статье
Практический материал

Разработка и Конфигурация · 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) и сравнить полученные строки или их хеши. Такой подход удобен для журналирования: вместо хранения копии табличной части сохраняется только хеш, и изменение любой строки мгновенно обнаруживается.

Сравнение способов

Попарный перебор по индексу

Подходит для проверки полного совпадения с учётом порядка строк; не находит перестановки и медленен на больших объёмах

Свёртка таблиц значений

Оптимален для сверки товаров и сумм без учёта порядка; показывает величину расхождения, но требует одинаковой структуры колонок

Запрос с полным соединением

Лучший выбор для больших таблиц и выборочного сравнения; требует аккуратности с дублями ключевых строк

Сравнение итогов и хешей

Самое быстрое для ответа «изменилось или нет»; не показывает, где именно расхождение

Как проверить результат сравнения

После внедрения любого из способов проверьте его на контрольных примерах. Создайте пару идентичных табличных частей — результат должен быть «равно». Затем измените одну строку, добавьте строку, удалите строку и поменяйте две строки местами: убедитесь, что алгоритм реагирует именно так, как задумано, а перестановка либо игнорируется, либо фиксируется — в зависимости от требований.

Для способа со свёрткой полезно вывести строки с ненулевым остатком в сообщение или табличный документ: это позволяет пользователю сразу увидеть, по какой номенклатуре и на какую сумму расхождение, вместо сухого «таблицы не совпадают».

Контрольные точки

Как проверить результат

Идентичные таблицы
Норма

Результат сравнения — совпадение, список расхождений пуст

Тревожный признак

Найдены различия — проверьте типы колонок и округление

Перестановка строк
Норма

Поведение соответствует требованию (игнорируется или фиксируется)

Тревожный признак

Свёртка фиксирует перестановку — значит, в группировку попала лишняя колонка

Разное число знаков после запятой
Норма

Расхождение в пределах заданной точности не фиксируется

Тревожный признак

Ложные расхождения на копейки — добавьте округление перед сравнением

Типичные ошибки при сравнении табличных частей

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

Типичные ошибки
01
Сравнение по всем колонкам выгрузки без фильтра: в результат попадают служебные поля, и таблицы «не совпадают» всегда
02
Забытая свёртка перед запросом при дублях номенклатуры: полное соединение перемножает строки, и разница искажается
03
Сравнение чисел без округления: расхождение в третьем знаке после запятой трактуется как различие документов
04
Сравнение ссылок по строковому представлению: два одинаковых элемента с разным представлением считаются разными
05
Игнорирование знака при объединении таблиц для свёртки: одинаковые строки суммируются вместо взаимного обнуления

Отдельная ошибка — сравнение табличной части из формы с данными объекта в базе без учёта модифицированности. Пользователь мог изменить строки, но не записать документ; запрос к базе в этот момент вернёт старые данные, и сравнение будет некорректным.

Итог

Что важно запомнить

Сначала определите критерий сравнения: порядок строк, состав колонок, допустимая точность чисел. Для сверки без учёта порядка используйте выгрузку и свёртку с инверсией знака, для больших объёмов — запрос с полным соединением, для проверки факта изменения — итоги или хеш. Всегда проверяйте алгоритм на контрольных примерах и работайте с реальными документами через копию базы.

Частые вопросы

Как сравнить табличные части двух разных документов?

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

Можно ли сравнить табличные части без программирования?

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

Как учесть порядок строк при сравнении?

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

Почему свёртка показывает расхождение, хотя таблицы визуально одинаковые?

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

Как сравнить табличную часть до и после изменения пользователем?

При открытии формы или в начале редактирования сохраните копию выгрузки табличной части в реквизит формы или переменную модуля. При записи или закрытии сравните текущую табличную часть с сохранённой копией любым из описанных способов — для этого сценария обычно достаточно попарного перебора или сравнения итогов.

Что делать, если табличные части содержат тысячи строк и сравнение тормозит?

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