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