Работа с таблицами значений в 1С:Предприятие — одна из самых частых задач при разработке конфигураций, отчетов или обработок. Но даже опытные программисты иногда сталкиваются с неочевидными нюансами при сравнении строк: почему Строка1 = Строка2 возвращает Ложь, хотя визуально данные идентичны? Или как эффективно найти различия между двумя большими таблицами без циклов по всем ячейкам?

В этой статье разберем 5 практических способов сравнения строк в таблицах значений 1С 8.3 (актуально и для 8.2), включая сравнение по индексу, по содержимому, с учетом типов данных и структуры колонок. Особое внимание уделим типичным ошибкам при сравнении ссылочных типов (СправочникСсылка, ДокументСсылка) и динамических списков, которые часто становятся источником багов в коде.

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

1. Базовые методы сравнения строк по индексу

Самый простой способ — сравнить строки по их порядковому номеру (индексу) в таблице. Это актуально, когда вам нужно проверить, изменилось ли положение строки после сортировки или фильтрации.

Для этого используйте метод Получить() с указанием индекса:

ТаблицаЗначений.Строка1 = ТаблицаЗначений.Получить(0); // Первая строка

ТаблицаЗначений.Строка2 = ТаблицаЗначений.Получить(1); // Вторая строка

Если Строка1 = Строка2 Тогда

Сообщить("Строки с индексами 0 и 1 идентичны");

Иначе

Сообщить("Строки различаются");

КонецЕсли;

  • Плюсы: максимально быстрый способ, не требует обхода всех колонок.
  • ⚠️ Минусы: сравниваются именно объекты строк, а не их содержимое. Если в таблице изменилось значение в одной ячейке, но индексы строк остались прежними, метод вернет Истина.
  • 🔄 Когда использовать: для проверки порядка строк после операций сортировки или перемещения.
⚠️ Внимание: Индексация строк в таблице значений начинается с 0, а не с 1, как в некоторых других коллекциях 1С. Ошибка с неверным индексом приведет к исключению "Индекс вне границ".
📊 Какой способ сравнения строк вы используете чаще?
По индексу
По содержимому всех колонок
По ключевому полю
С помощью временной таблицы
Другой

2. Сравнение по содержимому всех колонок

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

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

Процедура СравнитьСтрокиПоСодержимому(Таблица, Индекс1, Индекс2)

Строка1 = Таблица.Получить(Индекс1);

Строка2 = Таблица.Получить(Индекс2);

Для Каждого Колонка Из Таблица.Колонки Цикл

Если Строка1[Колонка.Имя] <> Строка2[Колонка.Имя] Тогда

Возврат Ложь;

КонецЕсли;

КонецЦикла;

Возврат Истина;

КонецПроцедуры;

Альтернативный вариант — использовать встроенный метод ТаблицаЗначений.Сравнить(), но он сравнивает целиком две таблицы, а не отдельные строки:

Таблица1 = Новый ТаблицаЗначений;

Таблица1.Колонки.Добавить("Наименование");

Таблица1.Добавить().Наименование = "Товар 1";

Таблица2 = Новый ТаблицаЗначений;

Таблица2.Колонки.Добавить("Наименование");

Таблица2.Добавить().Наименование = "Товар 1";

// Сравним таблицы (а не строки!)

Результат = Таблица1.Сравнить(Таблица2, Истина); // Второй параметр - сравнивать структуру

  • 🔍 Нюанс: При сравнении ссылочных типов (например, СправочникСсылка.Номенклатура) метод вернет Ложь, даже если ссылки указывают на один и тот же объект, но были получены разными способами (например, через выборку и прямое создание).
  • 🛠 Решение: Используйте метод Ссылка1.Сравнить(Ссылка2) для ссылочных типов.

Проверьте количество колонок в таблице|Убедитесь, что типы данных колонок совпадают|Для ссылочных типов используйте метод Сравнить()|Обработайте исключение "Индекс вне границ"-->

3. Сравнение по ключевому полю

В большинстве случаев сравнивать все колонки избыточно. Достаточно проверить уникальный идентификатор строки — например, Код, Артикул или Ссылка на объект.

Пример сравнения по полю "Код":

Функция СтрокиРавныПоКлючу(Таблица, Индекс1, Индекс2, ИмяКлючевогоПоля = "Код")

Строка1 = Таблица.Получить(Индекс1);

Строка2 = Таблица.Получить(Индекс2);

Возврат Строка1[ИмяКлючевогоПоля] = Строка2[ИмяКлючевогоПоля];

КонецФункции;

Способ сравнения Скорость Точность Когда использовать
По индексу ⚡ Мгновенно ❌ Низкая (сравниваются объекты, а не данные) Для проверки порядка строк
По всем колонкам 🐢 Медленно (зависит от количества колонок) ✅ Высокая Когда нужно точное совпадение
По ключевому полю ⚡⚡ Быстро ✅ Высокая (если ключ уникален) Для поиска дублей или связывания данных

Этот метод особенно полезен при работе с большими таблицами (тысячи строк), где поэлементное сравнение всех колонок заняло бы слишком много времени.

⚠️ Внимание: Если ключевое поле не уникально (например, несколько номенклатурных позиций имеют одинаковый Артикул), метод может давать ложноположительные результаты. Всегда проверяйте уникальность ключа перед использованием.

4. Сравнение с учетом типов данных

Одна из самых распространенных ошибок — игнорирование типов данных при сравнении. Например, строка с числом "100" и число 100 визуально одинаковы, но при сравнении через = результат будет Ложь.

Чтобы избежать таких ошибок, используйте приведение типов или универсальную функцию сравнения:

Функция УниверсальноеСравнение(Значение1, Значение2)

Попытка

// Попробуем сравнить как числа

Если Число(Значение1) = Число(Значение2) Тогда

Возврат Истина;

Иначе

// Если не числа - сравним как строки

Возврат Строка(Значение1) = Строка(Значение2);

КонецЕсли;

Исключение

// Если приведение не удалось - вернем Ложь

Возврат Ложь;

КонецПопытки;

КонецФункции;

Для сравнения дат используйте метод Дата1.Сравнить(Дата2), а для булевых значений — явное приведение к типу Булево().

  • 📅 Даты: Дата1 = Дата2 может работать некорректно из-за временной части. Используйте НачалоДня(Дата1) = НачалоДня(Дата2).
  • 🔢 Числа: Сравнение 100 = 100.00 вернет Истина, но 100 = "100"Ложь.
  • 🔗 Ссылки: Две ссылки на один объект могут не совпадать, если они из разных сеансов или баз. Используйте Ссылка1.УникальныйИдентификатор() = Ссылка2.УникальныйИдентификатор().
Почему сравнение ссылок может давать Ложь?

Даже если две ссылки указывают на один и тот же объект (например, элемент справочника), они могут считаться разными, если были получены:

1. Из разных сеансов 1С (например, через RPC или фоновое задание).

2. Из разных баз данных (в распределенной информационной базе).

3. Через разные механизмы (прямое создание ссылки vs. выборка из базы).

В таких случаях сравнивайте не сами ссылки, а их уникальные идентификаторы или ключевые поля (например, код или наименование).

5. Продвинутые методы: временные таблицы и запросы

Для сравнения больших таблиц (десятки тысяч строк) или сложных структур данных эффективнее использовать временные таблицы и язык запросов 1С. Это позволит перенести нагрузку на СУБД и ускорить обработку.

Пример сравнения двух таблиц значений через запрос:

// Создадим временные таблицы

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Таблица1.Наименование КАК Наименование1,

| Таблица2.Наименование КАК Наименование2

|ИЗ

| &Таблица1 КАК Таблица1

| ЛЕВОЕ СОЕДИНЕНИЕ &Таблица2 КАК Таблица2

| ПО Таблица1.Код = Таблица2.Код

|ГДЕ

| Таблица1.Наименование <> Таблица2.Наименование

| ИЛИ Таблица2.Наименование ЕСТЬ NULL";

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

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

Результат = Запрос.Выполнить();

Если Результат.Пустой() Тогда

Сообщить("Все строки совпадают");

Иначе

Сообщить("Найдены различия!");

КонецЕсли;

Преимущества этого подхода:

  • 🚀 Производительность: Запрос выполняется на стороне СУБД, что в десятки раз быстрее, чем обход строк в 1С.
  • 🔍 Гибкость: Можно сравнивать не только на полное совпадение, но и с учетом условий (например, "цена отличается более чем на 10%").
  • 📊 Результирующая выборка: Можно сразу получить список различий, а не только факт их наличия.
⚠️ Внимание: При использовании временных таблиц в запросах убедитесь, что структуры сравниваемых таблиц значений совпадают (одинаковые имена и типы колонок). Иначе запрос завершится с ошибкой.
💡

Если вам нужно сравнить таблицы с разной структурой, предварительно приведите их к общему виду с помощью метода ТаблицаЗначений.СкопироватьКолонки() или создайте временную таблицу с нужными колонками.

6. Типичные ошибки и как их избежать

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

  1. Сравнение ссылок без учета сеанса

    Проблема: Две ссылки на один объект (например, элемент справочника) не совпадают при сравнении через =.

    Решение: Используйте Ссылка1.Сравнить(Ссылка2) или сравнивайте уникальные идентификаторы.

  2. Игнорирование регистра при сравнении строк

    Проблема: "Товар" и "товар" считаются разными строками.

    Решение: Приводите строки к одному регистру с помощью Строка1 = Строка(Строка2).ВРегистре(Регистр.Прописью).

  3. Сравнение чисел и строк

    Проблема: 100 и "100" не совпадают при прямом сравнении.

    Решение: Явно приводите типы с помощью Число() или Строка().

  4. Неучтенные пустые значения

    Проблема: Неопределено, NULL и пустая строка "" обрабатываются по-разному.

    Решение: Используйте функцию ЗначениеЗаполнено() для проверки.

Чтобы минимизировать ошибки, всегда тестируйте сравнение на реальных данных, включая крайние случаи (пустые строки, NULL, максимальные значения чисел и т.д.).

1. Совпадают ли типы данных сравниваемых значений.

2. Учитываются ли особенности ссылочных типов (сеансы, базы данных).

3. Обрабатываются ли пустые значения и NULL корректно.-->

FAQ: Ответы на частые вопросы

Как сравнить две таблицы значений полностью, а не отдельные строки?

Используйте метод ТаблицаЗначений.Сравнить():

Результат = Таблица1.Сравнить(Таблица2, Истина); // Второй параметр - сравнивать структуру колонок

Если Результат Тогда

Сообщить("Таблицы идентичны");

Иначе

Сообщить("Таблицы различаются");

КонецЕсли;

Для детального анализа различий используйте запрос с ПОЛНОЕ СОЕДИНЕНИЕ.

Почему при сравнении строк с одинаковыми данными возвращается Ложь?

Наиболее вероятные причины:

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

Чтобы диагностировать проблему, выведите в отладчик значения всех колонок для обеих строк:

Для Каждого Колонка Из Таблица.Колонки Цикл

Сообщить(Строка(Колонка.Имя) + ": " + Строка(Строка1[Колонка.Имя]) + " | " + Строка(Строка2[Колонка.Имя]));

КонецЦикла;

Как сравнить строки с учетом погрешности для числовых значений?

Для сравнения чисел с допустимой погрешностью (например, при работе с плавающими значениями) используйте функцию:

Функция ЧислаРавныСПогрешностью(Число1, Число2, Погрешность = 0.0001)

Возврат Абс(Число1 - Число2) <= Погрешность;

КонецФункции;

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

Если ЧислаРавныСПогрешностью(100.00001, 100.00002, 0.0001) Тогда

Сообщить("Числа равны с учетом погрешности");

КонецЕсли;

Можно ли сравнить строки из разных таблиц значений?

Да, но необходимо учитывать:

  1. Структуры таблиц (имена и типы колонок) должны совпадать.
  2. Для сравнения используйте поэлементный обход колонок или временные таблицы в запросе.
  3. Если структуры различаются, предварительно скопируйте данные в таблицу с одинаковой структурой:
ОбщаяТаблица = Новый ТаблицаЗначений;

ОбщаяТаблица.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));

ОбщаяТаблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

// Скопируем данные из обеих таблиц

Для Каждого Строка Из Таблица1 Цикл

НоваяСтрока = ОбщаяТаблица.Добавить();

НоваяСтрока.Наименование = Строка.Наименование;

НоваяСтрока.Количество = Строка.Количество;

КонецЦикла;

Как ускорить сравнение больших таблиц (100 000+ строк)?

Для оптимизации производительности:

  • 🚀 Используйте запросы: Перенесите сравнение на сторону СУБД.
  • 🔑 Сравнивайте по ключевым полям: Не обходите все колонки, если достаточно проверить уникальный идентификатор.
  • 🧹 Индексируйте временные таблицы: В запросе создавайте индексы по полям, по которым идет сравнение.
  • 🔄 Разбивайте на пакеты: Сравнивайте данные порциями по 1000-5000 строк.

Пример оптимизированного запроса:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ РАЗЛИЧНЫЕ

| Т1.Код КАК Код

|ИЗ

| &Таблица1 КАК Т1

|ГДЕ НЕ Т1.Код В (

| ВЫБРАТЬ

| Т2.Код

| ИЗ

| &Таблица2 КАК Т2

| )

| ИЛИ Т1.Наименование <> (

| ВЫБРАТЬ

| Т2.Наименование

| ИЗ

| &Таблица2 КАК Т2

| ГДЕ Т2.Код = Т1.Код

| )";