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

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

Как работают соединения в 1С: подробное руководство по запросам

Разбираем соединения таблиц в запросах 1С: левое, правое, внутреннее и полное соединение, синтаксис, типичные ошибки, дубли строк и способы проверки результата.

Соединения в запросах 1С — основной способ собрать данные из нескольких таблиц в один результат: например, вывести заказы вместе с контрагентами, остатки вместе с ценами или документы вместе с их табличными частями. Без понимания того, как платформа сопоставляет строки двух таблиц, легко получить задвоенные суммы, потерянные записи или запрос, который выполняется в десятки раз дольше необходимого.

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

Материал рассчитан на разработчиков и внедренцев, которые пишут запросы в консоли запросов, в модулях или в СКД. Примеры приведены на встроенном языке запросов 1С и применимы к типовым и самописным конфигурациям на управляемых и обычных формах.

Что такое соединение и как платформа сопоставляет строки

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

Условие соединения может включать равенство полей, сравнения, проверку вхождения в список и даже соединение без условия (декартово произведение), хотя последнее в реальных запросах почти не нужно. Типичное условие — равенство ссылочных полей: Заказы.Контрагент = Контрагенты.Ссылка.

Важно понимать: соединение выполняется логически до применения итогов и группировок. Поэтому ошибка в условии соединения не всегда видна по тексту запроса — она проявляется в завышенных суммах после СУММА() или в лишних строках отчёта.

Виды соединений: левое, правое, внутреннее, полное

Левое соединение (ЛЕВОЕ СОЕДИНЕНИЕ) возвращает все строки левой таблицы. Для строк, которым не нашлось пары справа, поля правой таблицы заполняются значением NULL. Это самый частый вид соединения в учётных задачах: например, вывести всех контрагентов и их заказы, включая контрагентов без заказов.

Внутреннее соединение (ВНУТРЕННЕЕ СОЕДИНЕНИЕ) оставляет только те строки, для которых пара нашлась в обеих таблицах. Если у контрагента нет заказов — он в результат не попадёт. Такой вариант подходит, когда нужны только факты: проведённые документы с движениями, товары с ненулевыми остатками.

Правое соединение зеркально левому: сохраняются все строки правой таблицы. На практике правое соединение используют редко — проще поменять таблицы местами и написать левое, так запрос читается естественнее. Полное соединение (ПОЛНОЕ СОЕДИНЕНИЕ) возвращает все строки обеих таблиц, подставляя NULL там, где пары нет. Оно полезно для сверки двух наборов данных: например, сравнить остатки в учёте и остатки по данным склада и увидеть расхождения в обе стороны.

Сравнение видов соединений

Левое

Все строки левой таблицы, справа NULL при отсутствии пары. Стандарт для справочник + документы.

Внутреннее

Только совпавшие пары. Подходит, когда нужны лишь факты наличия связи, ускоряет запрос.

Правое

Зеркало левого. Обычно заменяется левым с перестановкой таблиц.

Полное

Все строки обеих таблиц с NULL с обеих сторон. Применяется для сверки расхождений двух наборов данных.

Синтаксис и практические примеры

Базовый пример левого соединения справочника с табличной частью документа:

ВЫБРАТЬ

Номенклатура.Ссылка КАК Товар,

Продажи.Количество КАК Количество

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваров.Товары КАК Продажи

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

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

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

bsl
ВЫБРАТЬ
	Заказы.Ссылка КАК Заказ,
	ЕСТЬNULL(Оплаты.СуммаОплаты, 0) КАК Оплачено
ИЗ
	Документ.ЗаказПокупателя КАК Заказы
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОплатыЗаказов КАК Оплаты
		ПО Заказы.Ссылка = Оплаты.Заказ

Соединения с виртуальными таблицами регистров

Самая частая и самая опасная ошибка — соединяться с виртуальной таблицей регистра (Остатки, Обороты, СрезПоследних) без параметров. Если написать РегистрНакопления.ТоварыНаСкладах.Остатки без указания периода и условий, платформа построит срез по всей таблице итогов, а при больших объёмах запрос может выполняться минутами.

Правильный подход — передавать параметры виртуальной таблицы в скобках: период, условие по измерениям. Например: Остатки(&Период, Склад = &Склад). Условия в параметрах виртуальной таблицы отрабатывают на уровне СУБД до соединения, что резко сокращает объём обрабатываемых данных. Условие, вынесенное в секцию ГДЕ после соединения, такого эффекта не даёт.

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

Дубли строк и NULL: типичные проблемы и их диагностика

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

Диагностируйте так: уберите группировку и итоги, выведите детальные строки и посмотрите, какие поля дублируются. Затем решите, какая из таблиц должна быть «детальной»: либо сгруппируйте правую таблицу во временной таблице до соединения (одна строка на ключ), либо осознанно оставьте детализацию и группируйте только нужные поля.

Вторая типичная ситуация — значения NULL после левого соединения. Сравнение NULL с чем-либо через обычное равенство в секции ГДЕ не сработает: условие ГДЕ Оплаты.Сумма > 0 отбросит и строки без оплат, фактически превратив левое соединение во внутреннее. Проверки на NULL делайте через ЕСТЬ NULL, а подстановку значений — через ЕСТЬNULL().

Типичные ошибки
01
Условие по правой таблице в секции ГДЕ без учёта NULL — левое соединение неожиданно превращается во внутреннее, строки теряются.
02
Соединение с виртуальной таблицей без параметров — резкое падение производительности и лишние блокировки.
03
Соединение по неуникальному ключу без группировки — задвоение сумм в итогах.
04
Использование ЕСТЬNULL только в полях выборки, но не в условиях соединения и отбора — несогласованные результаты.
05
Соединение со СрезПоследних на текущую дату вместо даты документа — неверные значения для старых документов.

Производительность: как не замедлить базу

Скорость соединения определяется тем, может ли СУБД быстро найти пару для каждой строки. Соединение по ссылке или по индексированным измерениям регистра работает быстро. Соединение по вычисляемому выражению, по строковому полю без индекса или по условию с функцией (например, ПОДСТРОКА) заставляет СУБД перебирать таблицу целиком.

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

Порядок оптимизации запроса с соединениями
  1. 1
    Сократите левую таблицу отбором до соединения: меньше строк — меньше поисков пары.
  2. 2
    Передайте период и условия в параметры виртуальных таблиц регистров.
  3. 3
    Проверьте, что соединение идёт по ссылке или индексированным полям, без функций в условии ПО.
  4. 4
    Убедитесь, что правая таблица сгруппирована до одного значения на ключ, если детализация не нужна.
  5. 5
    Замерьте время выполнения в консоли запросов и сравните с исходным вариантом.

Проверка результата и критерии правильного запроса

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

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

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

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

Число строк результата
Норма

Совпадает с левой таблицей при связи 1:1 или закономерно больше при 1:N

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

Строк больше ожидаемого без причины — дубли из-за неуникального ключа

Суммы по итогам
Норма

Совпадают с типовым отчётом или запросом без соединения

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

Суммы кратно завышены — задвоение; часть данных отсутствует — потеря строк

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

NULL только там, где пары действительно нет, заменены через ЕСТЬNULL

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

NULL в строках, где данные точно существуют, — ошибка в условии ПО

FAQ

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

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

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

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

Как вывести только записи, для которых нет пары во второй таблице?

Используйте левое соединение с условием ГДЕ ПраваяТаблица.Поле ЕСТЬ NULL. Так получают, например, товары без движений за период или контрагентов без заказов. Альтернатива — конструкция НЕ В с подзапросом, но вариант с соединением обычно быстрее и читабельнее.

Можно ли соединять таблицы по нескольким условиям?

Да, условия после ПО объединяются логическими И и ИЛИ: например, ПО Остатки.Номенклатура = Цены.Номенклатура И Остатки.Склад = Цены.Склад. Учитывайте, что чем сложнее условие и чем меньше оно опирается на индексированные поля, тем медленнее соединение.

Почему запрос с соединением к регистру работает медленно?

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

Что выбрать: соединение или объединение запросов?

Это разные операции. Соединение складывает поля двух таблиц в одну строку по условию связи. Объединение (ОБЪЕДИНИТЬ ВСЕ) складывает строки однотипных выборок друг под другом. Если нужно «присоединить сбоку» дополнительные поля — это соединение; если нужно собрать в один список данные из разных источников — объединение.

Итог

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

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