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