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