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