Разработка и Конфигурация · 12 мин
Как сравнить две таблицы в запросе 1С
Как сравнить две таблицы в запросе 1С: ПОЛНОЕ СОЕДИНЕНИЕ, ЛЕВОЕ СОЕДИНЕНИЕ с NULL, временные таблицы, примеры кода, типичные ошибки и проверка результата.
Сравнение двух таблиц — типовая задача при разработке отчётов и обработок в 1С: нужно найти строки, которые есть в одной таблице и отсутствуют в другой, показать расхождения по количеству или сумме, либо свести план с фактом. В языке запросов 1С для этого используются соединения — левое, правое, полное и внутреннее — в сочетании с проверкой на NULL и агрегатными функциями.
Ключевая идея проста: вы соединяете две выборки по ключевым полям (например, по номенклатуре и складу) и анализируете, где совпадений нет. Отсутствие строки после соединения проявляется как NULL в полях «пустой» стороны, и именно это значение становится маркером расхождения.
Ниже разобраны основные сценарии: поиск отсутствующих строк, полное сравнение «обе стороны», сравнение по значениям, работа с временными таблицами и внешними источниками данных, а также типичные ошибки, которые приводят к неверному результату или к падению производительности.
Какие виды соединений использовать для сравнения
В языке запросов 1С доступны четыре вида соединений, и каждый решает свою задачу сравнения. ВНУТРЕННЕЕ СОЕДИНЕНИЕ оставляет только совпадающие строки — оно отвечает на вопрос «что есть в обеих таблицах». ЛЕВОЕ СОЕДИНЕНИЕ берёт все строки первой таблицы и подставляет NULL там, где пары не нашлось — это основной инструмент поиска отсутствующих записей.
ПРАВОЕ СОЕДИНЕНИЕ зеркально левому и нужно редко: проще поменять таблицы местами и оставить левое. ПОЛНОЕ СОЕДИНЕНИЕ объединяет оба множества и показывает расхождения с обеих сторон одновременно — это самый наглядный вариант для отчёта «сверка», когда важно видеть и «есть в первой, нет во второй», и наоборот.
Сравнение вариантов соединений
Только совпадения. Подходит, когда нужно сравнить значения по общим строкам, а отсутствующие не интересуют.
Строки первой таблицы, которых нет во второй. Основной приём для поиска отсутствующих документов или позиций.
Расхождения в обе стороны одним запросом. Оптимально для сверки двух независимых источников.
Альтернатива полному соединению, когда нужно явно пометить направление расхождения текстом.
Поиск строк, которых нет во второй таблице
Классическая задача: есть список номенклатуры из заказа и список отгруженного — нужно найти, что не отгружено. Решается левым соединением с фильтром по NULL:
ВЫБРАТЬ
Заказ.Номенклатура КАК Номенклатура,
Заказ.Количество КАК Заказано
ИЗ
Заказ КАК Заказ
ЛЕВОЕ СОЕДИНЕНИЕ Отгрузка КАК Отгрузка
ПО Заказ.Номенклатура = Отгрузка.Номенклатура
ГДЕ
Отгрузка.Номенклатура ЕСТЬ NULL
Условие «ЕСТЬ NULL» отсекает все совпавшие строки, оставляя только те, для которых во второй таблице пары не нашлось. Важно проверять на NULL именно поле соединения (или ключ) второй таблицы — проверка необязательного реквизита даст ложные срабатывания, если этот реквизит сам по себе может быть пустым.
Если ключ составной, условие соединения перечисляется через И: «ПО Заказ.Номенклатура = Отгрузка.Номенклатура И Заказ.Склад = Отгрузка.Склад». Чем точнее ключ, тем корректнее сравнение: соединение только по номенклатуре скроет расхождения между складами.
Полное сравнение: расхождения в обе стороны
Когда обе таблицы независимы — например, данные учётной системы и выгрузка из внешнего источника — нужно видеть расхождения симметрично. Для этого используется ПОЛНОЕ СОЕДИНЕНИЕ:
ВЫБРАТЬ
ЕСТЬNULL(Учет.Номенклатура, Выгрузка.Номенклатура) КАК Номенклатура,
Учет.Количество КАК ПоУчету,
Выгрузка.Количество КАК ПоВыгрузке,
ЕСТЬNULL(Учет.Количество, 0) - ЕСТЬNULL(Выгрузка.Количество, 0) КАК Разница
ИЗ
Учет КАК Учет
ПОЛНОЕ СОЕДИНЕНИЕ Выгрузка КАК Выгрузка
ПО Учет.Номенклатура = Выгрузка.Номенклатура
Обратите внимание на два приёма. Первый — функция ЕСТЬNULL в поле ключа: при полном соединении ключ может оказаться NULL с любой стороны, поэтому берём первое непустое значение. Второй — вычисляемое поле «Разница», где NULL заменяется нулём, иначе арифметика с NULL даст NULL и расхождение не будет видно числом.
Чтобы вывести только расхождения, добавьте в секцию ГДЕ условие вида: «Учет.Номенклатура ЕСТЬ NULL ИЛИ Выгрузка.Номенклатура ЕСТЬ NULL ИЛИ ЕСТЬNULL(Учет.Количество, 0) <> ЕСТЬNULL(Выгрузка.Количество, 0)». Так вы получите компактную таблицу исключительно с проблемными строками.
ГДЕ
Учет.Номенклатура ЕСТЬ NULL
ИЛИ Выгрузка.Номенклатура ЕСТЬ NULL
ИЛИ ЕСТЬNULL(Учет.Количество, 0) <> ЕСТЬNULL(Выгрузка.Количество, 0)Сравнение с временными таблицами и внешними данными
На практике сравниваемые наборы редко лежат в готовом виде в одном регистре. Обычно каждую сторону сначала собирают во временную таблицу: помещают туда данные из регистра накопления с отбором по периоду, агрегируют по нужным измерениям, а затем соединяют уже подготовленные выборки. Это упрощает итоговый запрос и ускоряет его выполнение.
Типовая структура пакетного запроса выглядит так: первый запрос формирует таблицу «План» с ПОМЕСТИТЬ План, второй — таблицу «Факт» с ПОМЕСТИТЬ Факт, третий соединяет План и Факт полным соединением и вычисляет разницу. Менеджер временных таблиц при этом один на весь пакет.
Если одна из сторон — произвольная таблица значений (например, загруженная из Excel или полученная из веб-сервиса), её передают в запрос как параметр через конструкцию «ВЫБРАТЬ ... ИЗ &Таблица КАК Таблица» с указанием полей и помещают во временную таблицу. Дальше сравнение идёт стандартным соединением. Учтите: типы колонок таблицы значений должны быть определены явно, иначе запрос может не выполниться или сравнение по значениям сработает некорректно.
- 1Соберите первую сторону во временную таблицу с нужными отборами и группировкой по ключу сравнения.
- 2Соберите вторую сторону аналогично, приведя ключи к тем же типам и измерениям.
- 3Соедините таблицы полным или левым соединением по составному ключу.
- 4Добавьте вычисляемые поля-разницы с ЕСТЬNULL для числовых показателей.
- 5Отфильтруйте результат условием на NULL или на ненулевую разницу.
- 6Проверьте итоги: суммы по обеим сторонам до фильтра должны сходиться с исходными данными.
Сравнение агрегированных данных и дублей
Частая ловушка — соединение неагрегированных таблиц. Если в первой таблице по одной номенклатуре три строки, а во второй две, соединение даст декартово перемножение внутри ключа: шесть строк вместо одной. Суммы после такого соединения будут завышены, и сверка «не сойдётся», хотя данные корректны.
Правило простое: перед соединением каждую сторону сворачивайте до уровня ключа сравнения через СГРУППИРОВАТЬ ПО с агрегатами СУММА, КОЛИЧЕСТВО, МАКСИМУМ. Если детализация нужна в результате — добавьте её в ключ, а не отказывайтесь от группировки.
Для поиска самих дублей внутри одной таблицы используют группировку с условием «ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1». Это полезно как предварительная проверка качества данных перед сравнением: если в одной из таблиц есть непредусмотренные дубли по ключу, сравнение гарантированно даст искажённый результат.
Производительность и ограничения
Полное соединение — самая тяжёлая операция из перечисленных: платформа вынуждена обработать оба набора целиком и не всегда может использовать индексы эффективно. На больших таблицах (сотни тысяч строк) сначала сократите объёмы отборами по периоду и организации, затем сгруппируйте, и только потом соединяйте.
Убедитесь, что поля соединения индексированы. Для регистров индексирование определяется структурой измерений, поэтому соединение по измерениям регистра работает быстрее, чем по реквизитам. Если соединяете по реквизиту, в типовых конфигурациях для него часто можно включить индексирование в свойствах объекта — но это решение уровня изменения конфигурации, применяйте его осознанно.
Ещё одно ограничение: в запросах к виртуальным таблицам регистров параметры виртуальной таблицы (период, условия) следует задавать в скобках самой виртуальной таблицы, а не выносить в секцию ГДЕ после соединения. Иначе СУБД сначала выберет весь регистр, а потом отфильтрует — на больших базах это кратно увеличивает время выполнения.
Проверка результата сравнения
Корректность сверки проверяется контрольными суммами. До применения фильтра расхождений сравните итоговые суммы по каждой стороне соединения с итогами исходных таблиц: они должны совпасть. Если итог после соединения больше исходного — в данных есть дубли по ключу и произошло перемножение строк.
Второй контроль — количественный: число строк с расхождениями должно быть объяснимо. Если левое соединение «нашло» отсутствующими почти все строки, скорее всего, ошибка в условии соединения (несовпадение типов, лишние пробелы в строковых ключах, разные представления дат). Проверьте несколько конкретных ключей вручную через консоль запросов.
Полезный приём — вывести служебное поле-статус: «Только в первой», «Только во второй», «Различается», «Совпадает» через конструкцию ВЫБОР КОГДА ... ТОГДА. Такой статус делает результат самодокументируемым и упрощает визуальную проверку в отчёте.
Как проверить результат сверки
Равна итогу исходной таблицы
Сумма выросла — дубли по ключу и перемножение строк
Расхождений немного, они объяснимы бизнес-ситуацией
Расходится почти всё — ошибка в условии соединения или типах полей
Числовое значение, ноль при совпадении
NULL или пусто — забыли ЕСТЬNULL в вычислении
Заполнены с обеих сторон через ЕСТЬNULL
Пустые ключи при полном соединении
FAQ
Чем отличается ПОЛНОЕ СОЕДИНЕНИЕ от двух левых через ОБЪЕДИНИТЬ ВСЕ?
Результат близок, но полное соединение даёт одну строку на пару ключей, где видны обе стороны сразу, а конструкция с ОБЪЕДИНИТЬ ВСЕ выдаёт два независимых набора строк, которые придётся дополнительно сворачивать. Для отчёта-сверки полное соединение компактнее и обычно быстрее.
Как сравнить таблицы, если ключи имеют разные типы?
Приведите типы до соединения: например, преобразуйте значение через ВЫРАЗИТЬ или сравнивайте по представлению в крайнем случае. Лучшее решение — выровнять типы ещё на этапе формирования временных таблиц, чтобы соединение работало по одинаковым типам и могло использовать индексы.
Можно ли сравнить таблицу значений с таблицей базы без временной таблицы?
Нет, таблицу значений нельзя соединить с таблицей базы напрямую. Её нужно передать в запрос параметром, описать поля во вложенном запросе и поместить во временную таблицу — только после этого она участвует в соединениях наравне с таблицами базы данных.
Почему ЕСТЬ NULL не находит отсутствующие строки?
Чаще всего проверяется не то поле: если колонка второй таблицы сама может содержать NULL, условие сработает и на совпавшие строки. Проверяйте ключ соединения. Также убедитесь, что используется именно ЛЕВОЕ (а не ВНУТРЕННЕЕ) соединение — при внутреннем несовпавшие строки отбрасываются ещё до фильтра.
Как сравнить таблицы по нескольким числовым показателям сразу?
Добавьте в результат по вычисляемому полю-разнице на каждый показатель (с ЕСТЬNULL по обеим сторонам), а в условие ГДЕ включите проверку, что хотя бы одна разница не равна нулю, объединяя условия через ИЛИ. Для допуска по погрешности сравнивайте модуль разницы с порогом.
Что быстрее: соединение или вложенный запрос с В (ИЕРАРХИЯ)?
Для поиска отсутствующих строк вариант «ГДЕ НЕ Ключ В (ВЫБРАТЬ Ключ ИЗ ВтораяТаблица)» иногда читается проще, но на больших объёмах левое соединение с ЕСТЬ NULL обычно предсказуемее по плану выполнения. На критичных по скорости запросах стоит проверить оба варианта в консоли на реальных данных.
Что важно запомнить
Сравнение таблиц в запросе 1С строится на соединениях: левое с ЕСТЬ NULL ищет отсутствующие строки, полное показывает расхождения в обе стороны. Перед соединением сворачивайте данные до ключа сравнения, приводите типы, используйте ЕСТЬNULL в вычислениях и проверяйте результат контрольными суммами.