К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как работает левое соединение в запросе 1С

Как работает левое соединение в запросе 1С: синтаксис, примеры, типичные ошибки, проверка на NULL и сравнение с другими типами соединений таблиц.

Левое соединение — один из самых часто используемых операторов в запросах 1С. Оно возвращает все строки левой таблицы и дополняет их данными из правой таблицы там, где условие связи выполняется. Если совпадения в правой таблице нет, поля из неё будут содержать значение NULL. Именно это поведение делает левое соединение основным инструментом для задач вида «показать все документы и, если есть, связанные оплаты» или «вывести всех сотрудников и их начисления, если они были».

Понимание механики левого соединения критично не только для корректности результата, но и для производительности. Неправильно составленное условие связи или фильтрация по полям правой таблицы в секции ГДЕ способны превратить левое соединение во внутреннее, а дубли в правой таблице — задвоить строки результата и исказить итоги по суммам и количествам.

Ниже разобраны синтаксис, логика обработки, типовые сценарии, работа со значениями NULL, ошибки разработчиков и способы проверить, что запрос возвращает именно то, что ожидалось.

Что делает оператор ЛЕВОЕ СОЕДИНЕНИЕ

В языке запросов 1С левое соединение записывается так: ЛЕВОЕ СОЕДИНЕНИЕ ИмяПравойТаблицы КАК Псевдоним ПО УсловиеСвязи. Запрос сначала берёт каждую строку левой таблицы, затем ищет в правой таблице строки, удовлетворяющие условию. Нашёл — подставляет значения, не нашёл — подставляет NULL во все поля, выбранные из правой таблицы.

Ключевые свойства, которые нужно держать в голове при построении запроса:

  • количество строк результата никогда не меньше количества строк левой таблицы (после её собственных отборов);
  • если в правой таблице несколько строк подходят под условие, строка левой таблицы продублируется — по одной строке на каждое совпадение;
  • порядок таблиц имеет значение: «А ЛЕВОЕ СОЕДИНЕНИЕ Б» и «Б ЛЕВОЕ СОЕДИНЕНИЕ А» — разные запросы с разным результатом;
  • ключевое слово НАРУЖНОЕ в синтаксисе 1С не используется — достаточно ЛЕВОЕ СОЕДИНЕНИЕ.

Синтаксис и минимальный рабочий пример

Типовая задача: вывести все товары из справочника «Номенклатура» и для тех, у кого есть остатки, показать количество на складе. Товары без остатков тоже должны присутствовать в отчёте.

ВЫБРАТЬ

Товары.Ссылка КАК Товар,

Остатки.КоличествоОстаток КАК Остаток

ИЗ

Справочник.Номенклатура КАК Товары

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки

ПО Товары.Ссылка = Остатки.Номенклатура

В результат попадут все элементы справочника. У товаров с остатками поле «Остаток» будет заполнено, у остальных — NULL. Если бы использовалось внутреннее соединение, товары без движений просто исчезли бы из выборки.

Условие связи может быть составным — через И. Например, при соединении с виртуальной таблицей остатков по нескольким измерениям: ПО Товары.Ссылка = Остатки.Номенклатура И Остатки.Склад = &Склад. Чем точнее условие, тем меньше лишних строк обрабатывает СУБД.

Как NULL влияет на результат и как с ним работать

Значение NULL — не ноль и не пустая строка. Это признак отсутствия значения. Любое сравнение с NULL через обычные операторы (=, <>, >) возвращает не Истина или Ложь, а NULL, поэтому такие условия в секции ГДЕ работают неочевидно и отбрасывают строки.

Для проверки на NULL используются специальные конструкции:

  • ПОЛЕ ЕСТЬ NULL — строка есть только в левой таблице, совпадений не найдено;
  • ПОЛЕ ЕСТЬ НЕ NULL — совпадение найдено;
  • ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) — подставляет значение вместо NULL, например ЕСТЬNULL(Остатки.КоличествоОстаток, 0);
  • ВЫБОР КОГДА Поле ЕСТЬ NULL ТОГДА ... ИНАЧЕ ... КОНЕЦ — для более сложной логики подстановки.

Практический приём «найти записи без пары»: соединить таблицы левым соединением и отобрать строки, где ключевое поле правой таблицы равно NULL. Так, например, находят товары без штрихкодов или документы без проведённых оплат.

bsl
ВЫБРАТЬ
	Товары.Ссылка КАК Товар
ИЗ
	Справочник.Номенклатура КАК Товары
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Штрихкоды КАК Штрихкоды
		ПО Товары.Ссылка = Штрихкоды.Владелец
ГДЕ
	Штрихкоды.Владелец ЕСТЬ NULL

Главная ловушка: условие в ГДЕ превращает левое соединение во внутреннее

Самая распространённая ошибка — фильтровать результат по полю правой таблицы в секции ГДЕ. Пример: запрос должен показать всех клиентов и их долги, но только по конкретному договору. Разработчик пишет левое соединение с регистром расчётов, а в ГДЕ добавляет «Расчеты.Договор = &Договор». Строки, где соединения не было, имеют NULL в поле «Договор», условие сравнения не выполняется — и такие клиенты выпадают из результата. Фактически получилось внутреннее соединение.

Правильные способы решить задачу:

  1. Перенести условие в секцию ПО соединения: ПО Клиенты.Ссылка = Расчеты.Контрагент И Расчеты.Договор = &Договор. Тогда фильтр применяется к правой таблице до соединения, а строки левой таблицы сохраняются.
  2. Использовать параметры виртуальной таблицы, если соединение идёт с виртуальной таблицей регистра.
  3. Если условие всё же нужно в ГДЕ, добавить альтернативу через NULL: ГДЕ (Расчеты.Договор = &Договор ИЛИ Расчеты.Договор ЕСТЬ NULL).
Типичные ошибки
01
Условие по полю правой таблицы в секции ГДЕ — строки без совпадений отбрасываются, левое соединение деградирует до внутреннего.
02
Соединение с таблицей, где несколько строк подходят под условие, — строки левой таблицы дублируются, итоги по суммам завышаются.
03
Сравнение поля с NULL через оператор = — условие никогда не выполняется, используйте ЕСТЬ NULL.
04
Соединение по неиндексированным полям больших таблиц без предварительного отбора — резкое падение производительности.

Дублирование строк и размножение итогов

Второй по частоте источник ошибок — множественные совпадения в правой таблице. Если соединить заказы с табличной частью оплат по ссылке на заказ, а оплат было три, заказ появится в результате трижды. При группировке с СУММА по полям левой таблицы итог утроится, что искажает отчётность и может привести к неверным управленческим решениям.

Способы борьбы:

  • предварительно сгруппировать правую таблицу во временной таблице или вложенном запросе, чтобы на один ключ приходилась одна строка;
  • использовать РАЗЛИЧНЫЕ, если нужны только уникальные комбинации;
  • группировать итоговый запрос по ключу левой таблицы и применять агрегатные функции осознанно — понимая, что суммируется;
  • проверять результат на тестовых данных, где заведомо известно количество строк и суммы.

Сравнение с другими типами соединений

Выбор типа соединения определяется тем, какие строки должны гарантированно попасть в результат. Краткое сопоставление:

Тип соединенияЧто попадает в результатТиповой сценарий
ВНУТРЕННЕЕТолько строки с совпадением в обеих таблицахДокументы, у которых обязательно есть движения
ЛЕВОЕВсе строки левой таблицы + совпадения справаВсе товары и их остатки, если есть
ПРАВОЕВсе строки правой таблицы + совпадения слеваРедко; обычно заменяется левым с перестановкой таблиц
ПОЛНОЕВсе строки обеих таблицСверка двух источников: что есть там и тут, и где расхождения

Правое соединение в практике почти не используется: любой запрос с правым соединением можно переписать левым, поменяв таблицы местами, и такой вариант легче читается. Полное соединение полезно при сверках, но требует аккуратной обработки NULL с обеих сторон.

Сравнение вариантов

Левое соединение

Подходит, когда основной список — левая таблица, а данные справа опциональны. Ограничение: фильтры по правой таблице требуют особой обработки.

Внутреннее соединение

Подходит, когда нужны только пары с гарантированным совпадением. Быстрее обрабатывается, но теряет строки без пары.

Полное соединение

Подходит для сверки двух источников. Ограничение: NULL возможен с обеих сторон, логика отбора сложнее.

Производительность и порядок построения запроса

Левое соединение само по себе не медленное — проблемы возникают из-за объёмов данных и отсутствия индексов по полям связи. Базовые рекомендации:

  • соединяйте таблицы по индексированным полям: ссылка, код, измерения регистра;
  • сокращайте правую таблицу до соединения — параметрами виртуальной таблицы, вложенным запросом или временной таблицей с отбором;
  • в больших запросах помещайте промежуточные результаты во временные таблицы и создавайте на них индексы (ИНДЕКСИРОВАТЬ ПО);
  • не выбирайте поля, которые не используются, — особенно из правой таблицы;
  • избегайте соединений по вычисляемым выражениям и функциям от полей — такие условия не используют индексы.

Проверить план и фактическую скорость выполнения помогает консоль запросов с замером времени, а на тяжёлых отчётах — технологический журнал и анализ запроса СУБД. Если запрос в отчёте СКД работает медленно, первым делом смотрите именно на соединения с виртуальными таблицами без параметров.

Порядок действий при построении запроса
  1. 1
    Определите главную таблицу — ту, все строки которой должны попасть в результат, и поставьте её слева.
  2. 2
    Добавьте ЛЕВОЕ СОЕДИНЕНИЕ с условием связи по индексированным полям.
  3. 3
    Условия по полям правой таблицы перенесите в секцию ПО или в параметры виртуальной таблицы.
  4. 4
    Обработайте NULL через ЕСТЬNULL для вычисляемых и итоговых полей.
  5. 5
    Проверьте результат на тестовых данных: количество строк левой таблицы, отсутствие дублей, корректность итогов.

Проверка результата: как убедиться, что запрос работает правильно

Перед тем как использовать запрос в отчёте или обработке, прогоните его через три контрольные точки. Первая — полнота: количество уникальных ключей левой таблицы в результате должно совпадать с количеством записей в самой левой таблице (с учётом её отборов). Если их меньше — где-то условие срезало строки.

Вторая — отсутствие размножения: сгруппируйте результат по ключу левой таблицы с КОЛИЧЕСТВО(*) и отсортируйте по убыванию. Значения больше ожидаемого указывают на множественные совпадения справа. Третья — корректность итогов: сверьте суммы по контрольным документам или регистру с эталонным отчётом конфигурации.

Контрольные точки

Как проверить результат

Количество строк результата
Норма

Не меньше числа строк левой таблицы после её отборов

Тревожный признак

Строк меньше — фильтр в ГДЕ срезает NULL-строки

Дубли по ключу левой таблицы
Норма

Одна строка на ключ либо осознанное количество

Тревожный признак

Неожиданные дубли и завышенные суммы

Поля правой таблицы
Норма

NULL там, где совпадения нет, ЕСТЬNULL подставляет значения по умолчанию

Тревожный признак

Пустые значения ломают группировки и итоги

Время выполнения
Норма

Запрос выполняется за приемлемое время на реальном объёме данных

Тревожный признак

Резкий рост времени при увеличении объёма — нет индексов или лишние строки справа

Когда левое соединение не нужно: альтернативы

Не каждая задача требует соединения. Если данные правой таблицы нужны только для проверки существования связанной записи, а сами поля не выбираются, рассмотрите вариант с условием В (ВЫБРАТЬ ...) или В ИЕРАРХИИ — такие конструкции иногда читаются проще. Для подстановки одного реквизита из связанного объекта часто достаточно обращения через точку (разыменование), например Документ.Контрагент.ИНН, — но помните, что множественные разыменования в больших выборках тоже порождают неявные соединения.

В СКД вместо ручного соединения в тексте запроса иногда выгоднее использовать связи наборов данных на закладке «Связи наборов данных» — это даёт гибкость при настройке отчёта пользователем, хотя по сути под капотом выполняется то же левое соединение.

Маршрут решения

Как выбрать действие

Нужны все строки левой таблицы независимо от наличия связанных данныхИспользуйте ЛЕВОЕ СОЕДИНЕНИЕ, условия по правой таблице — в секции ПО
Нужны только пары с гарантированным совпадениемИспользуйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ — оно проще и обычно быстрее
Нужно найти записи без парыЛЕВОЕ СОЕДИНЕНИЕ + условие ключевое поле правой таблицы ЕСТЬ NULL
В правой таблице несколько строк на один ключСначала сгруппируйте правую таблицу во временной таблице, потом соединяйте

Частые вопросы

Чем левое соединение отличается от внутреннего на практике?

Внутреннее соединение оставляет только строки, для которых нашлась пара в обеих таблицах. Левое сохраняет все строки левой таблицы, даже если пары нет — тогда поля правой таблицы равны NULL. Выбор зависит от того, обязательна ли связанная запись для результата.

Почему после добавления условия в ГДЕ пропали строки из левой таблицы?

Условие по полю правой таблицы отбрасывает строки, где это поле равно NULL, то есть все несоединившиеся записи. Перенесите условие в секцию ПО соединения или добавьте вариант «ИЛИ поле ЕСТЬ NULL».

Как вывести ноль вместо NULL в поле остатка?

Используйте функцию ЕСТЬNULL(Поле, 0). Она возвращает значение поля, если оно не NULL, и указанное значение по умолчанию в противном случае. Это стандартный приём для числовых показателей в отчётах.

Почему после левого соединения удвоились суммы в итогах?

В правой таблице нашлось несколько строк, подходящих под условие связи, и строка левой таблицы продублировалась. Сгруппируйте правую таблицу заранее до одной строки на ключ или пересмотрите условие связи, добавив недостающие поля.

Можно ли соединять больше двух таблиц подряд?

Да, соединения можно выстраивать цепочкой: каждая следующая таблица присоединяется к результату предыдущих соединений. Важно следить, чтобы условия по полям «правых» таблиц не стояли в ГДЕ, иначе вся цепочка левых соединений превратится во внутренние.

Что быстрее: левое соединение или разыменование через точку?

Разыменование через точку платформа чаще всего реализует теми же соединениями на уровне СУБД, поэтому принципиальной разницы в скорости нет. Явное соединение предпочтительнее, когда нужно несколько полей из связанной таблицы или сложное условие связи, — оно читается и оптимизируется прозрачнее.

Итог

Что важно запомнить

Левое соединение сохраняет все строки левой таблицы и подставляет NULL в поля правой при отсутствии совпадения. Условия по правой таблице пишите в секции ПО, NULL обрабатывайте через ЕСТЬNULL и ЕСТЬ NULL, а результат проверяйте на полноту строк, отсутствие дублей и корректность итогов.