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