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