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