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

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

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

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

Метод 1. Использование встроенных функций БСП

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

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


// Выполняем первый запрос (эталонный)
Запрос1 = Новый Запрос(ТекстЭталона);
Результат1 = Запрос1.Выполнить().Выгрузить();

// Выполняем второй запрос (пользовательский)
Запрос2 = Новый Запрос(ТекстПользователя);
Результат2 = Запрос2.Выполнить().Выгрузить();

// Сравниваем результаты через БСП
Если ОбщегоНазначения.ДанныеСовпадают(Результат1, Результат2) Тогда
    Сообщить("Результаты запросов идентичны!");
Иначе
    Сообщить("Результаты различаются.");
КонецЕсли;

Проанализируем нюансы: этот метод чувствителен к порядку строк. Если два запроса возвращают одни и те же данные, но в разном порядке, функция вернет Ложь. Чтобы этого избежать, перед сравнением обе таблицы необходимо отсортировать по всем колонкам.

Метод 2. Ручное сравнение через таблицы значений

Если использование БСП невозможно или вы хотите реализовать собственную логику сравнения с детальным выводом различий, проанализируем алгоритм ручного сопоставления двух объектов ТаблицаЗначений.

Выясним основные этапы проверки:

  1. Проверка количества колонок и их имен. Если состав полей разный, данные заведомо не могут быть идентичными. Учитывайте также применение отбора компоновки данных, которое может динамически менять структуру выборки.
  2. Проверка количества строк. Если одна таблица содержит 10 записей, а другая 11 — сравнение можно прекращать.
  3. Сортировка. Это критически важный шаг. Без явной сортировки идентичные наборы данных могут быть признаны разными.
  4. Построчный обход. В цикле сравниваем каждое значение каждой колонки.

Для ускорения написания подобных алгоритмов можно использовать консоль кода с ИИ-помощником. Рассмотрим пример реализации функции сравнения:


Функция ТаблицыИдентичны(Таблица1, Таблица2)
    
    // 1. Проверяем количество колонок
    Если Таблица1.Колонки.Количество() <> Таблица2.Колонки.Количество() Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // 2. Проверяем количество строк
    Если Таблица1.Количество() <> Таблица2.Количество() Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Составляем список колонок для сортировки
    СтрокаКолонок = "";
    Для Каждого Колонка Из Таблица1.Колонки Цикл
        СтрокаКолонок = СтрокаКолонок + ?(СтрокаКолонок = "", "", ",") + Колонка.Имя;
    КонецЦикла;
    
    // 3. Сортируем обе таблицы
    Таблица1.Сортировать(СтрокаКолонок);
    Таблица2.Сортировать(СтрокаКолонок);
    
    // 4. Построчное сравнение
    Для Индекс = 0 По Таблица1.Количество() - 1 Цикл
        Строка1 = Таблица1[Индекс];
        Строка2 = Таблица2[Индекс];
        
        Для Каждого Колонка Из Таблица1.Колонки Цикл
            Если Строка1[Колонка.Имя] <> Строка2[Колонка.Имя] Тогда
                Возврат Ложь;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    
    Возврат Истина;
КонецФункции

Метод 3. Сравнение через механизм «Схема запроса»

Иногда задача стоит иначе: нужно понять, не возвращают ли запросы одинаковые данные, а одинакова ли их логическая структура. Например, если пользователь просто добавил лишний пробел или изменил регистр ключевого слова ВЫБРАТЬ на выбрать. Прямое сравнение строк здесь не поможет.

Для этих целей в платформе 8.3 предусмотрен объект СхемаЗапроса. Он позволяет разобрать текст запроса в древовидную структуру объектов. Проанализируем, как это работает:


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

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

// Теперь можно программно сравнить части запроса
// Например, количество выбираемых полей в первом пакете
Если Схема1.ПакетЗапросов[0].ВыбираемыеПоля.Количество() = Схема2.ПакетЗапросов[0].ВыбираемыеПоля.Количество() Тогда
    // Продолжаем проверку источников данных, условий ГДЕ и т.д.
КонецЕсли;

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

Метод 4. Сравнение на уровне СУБД (Метод исключения)

Для очень больших наборов данных выгрузка в ТаблицаЗначений может занять много памяти. В этом случае эффективно переложить задачу сравнения на саму СУБД. Мы можем объединить два запроса и проверить, есть ли между ними разница.

Рассмотрим алгоритм «контрольной суммы» записей:

  1. Выполняем первый запрос и помещаем его во временную таблицу ВТ_Данные1, добавив поле Счетчик со значением 1.
  2. Выполняем второй запрос и помещаем его во временную таблицу ВТ_Данные2, добавив поле Счетчик со значением -1.
  3. Используем ОБЪЕДИНИТЬ ВСЕ для обеих таблиц.
  4. Группируем результат по всем полям (кроме счетчика) и рассчитываем СУММА(Счетчик).

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


ТекстСравнения = 
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Все ИЗ (
|    ВЫБРАТЬ Т1.*, 1 КАК Счетчик ИЗ ВТ_Данные1 КАК Т1
|    ОБЪЕДИНИТЬ ВСЕ
|    ВЫБРАТЬ Т2.*, -1 КАК Счетчик ИЗ ВТ_Данные2 КАК Т2
|) КАК Совмещенные;
|
|ВЫБРАТЬ * ИЗ ВТ_Все 
|СГРУППИРОВАТЬ ПО [ВсеПоляЗапроса] 
|ИМЕЮЩИЕ СУММА(Счетчик) <> 0";

Метод 5. Быстрое сравнение через сериализацию

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

Важно: этот способ также требует предварительной сортировки таблиц и совпадения типов колонок.


// Используем внутреннее строковое представление
СтрокаТаблицы1 = ЗначениеВСтрокуВнутр(Результат1);
СтрокаТаблицы2 = ЗначениеВСтрокуВнутр(Результат2);

Если СтрокаТаблицы1 = СтрокаТаблицы2 Тогда
    Сообщить("Данные полностью совпадают");
КонецЕсли;

Также можно использовать СериализаторXDTO для выгрузки в XML или JSON, что позволит игнорировать некоторые специфические системные свойства объектов, сосредоточившись только на данных.

Важные замечания по типам данных

При сравнении результатов запросов всегда помните о следующих моментах:

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

← На главную