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