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

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

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

Как соединить таблицы в запросе 1С: виды соединений, синтаксис ЛЕВОЕ, ПРАВОЕ, ВНУТРЕННЕЕ и ПОЛНОЕ, условия связи, типичные ошибки и проверка результата.

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

Выбор типа соединения определяет, какие строки попадут в результат: все ли записи левой таблицы, только совпавшие пары или полное объединение обеих сторон. Неверный выбор — самая частая причина «пропавших» или задвоенных строк в отчётах.

Ниже разобраны все четыре вида соединений, синтаксис с примерами, типичные ошибки (дублирование строк, NULL вместо значений, лишние виртуальные таблицы) и способы проверить корректность результата до вывода его пользователю.

Виды соединений и когда какой применять

Язык запросов 1С поддерживает четыре типа соединений, аналогичные стандартному SQL. Различие между ними — в том, какие строки сохраняются, когда пары по условию связи не нашлось.

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

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

Базовый синтаксис соединения в запросе 1С

Соединение описывается в секции ИЗ. Каждой таблице обязательно даётся псевдоним через КАК, а условие связи указывается после ключевого слова ПО.

ВЫБРАТЬ

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

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

ИЗ

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

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

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

В этом примере левая таблица — справочник «Номенклатура», правая — виртуальная таблица остатков регистра накопления. В результат попадут все позиции справочника; для товаров без остатков поле Остаток будет равно NULL.

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

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

ЛЕВОЕ соединение: справочник с остатками и ценами

Классическая задача — вывести весь каталог товаров с остатками, не теряя позиции, которых нет на складе. Здесь подходит только ЛЕВОЕ соединение: ВНУТРЕННЕЕ отбросит товары без движений.

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

ВЫБРАТЬ

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

ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток

ИЗ

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

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

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

Функция ЕСТЬNULL заменяет NULL на ноль, чтобы в отчёте не было пустых ячеек и корректно работало суммирование. Это стандартный приём при любом ЛЕВОМ соединении с числовыми данными.

ВНУТРЕННЕЕ и ПОЛНОЕ соединения

ВНУТРЕННЕЕ соединение оставляет только пары, существующие в обеих таблицах. Оно уместно, когда строка без пары бессмысленна: например, при выборке проведённых документов и их движений по регистру — документ без движений в таком отчёте не нужен.

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

Учтите, что ПОЛНОЕ соединение требовательнее к ресурсам, а в некоторых сценариях его можно заменить объединением двух запросов с ЛЕВЫМ и ПРАВЫМ соединением через ОБЪЕДИНИТЬ, если это упрощает логику.

Что выбрать в типовых задачах

ЛЕВОЕ соединение

Справочник + остатки, цены, дополнительные реквизиты. Сохраняет все позиции основной таблицы; требует обработки NULL через ЕСТЬNULL.

ВНУТРЕННЕЕ соединение

Документы + движения, строки табличных частей + шапка. Быстрее и проще, но отбрасывает строки без пары.

ПОЛНОЕ соединение

Сверка двух наборов данных с поиском расхождений в обе стороны. Редкий сценарий, требует аккуратной работы с NULL с двух сторон.

Соединение нескольких таблиц и соединение с подзапросом

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

Справа от ключевого слова СОЕДИНЕНИЕ может стоять не только физическая или виртуальная таблица, но и вложенный запрос в скобках с собственным псевдонимом. Это удобно, когда данные нужно предварительно сгруппировать или отфильтровать.

ЛЕВОЕ СОЕДИНЕНИЕ (

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

СУММА(Продажи.Количество) КАК Продано

ИЗ

РегистрНакопления.Продажи.Обороты(&Начало, &Конец, , ) КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Номенклатура

) КАК ИтогиПродаж

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

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

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

Типичные ошибки при соединении таблиц

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

Вторая группа ошибок связана с NULL: забытый ЕСТЬNULL приводит к пустым значениям в итогах и к некорректным сравнениям, потому что любое сравнение с NULL даёт ложь. Проверку на отсутствие значения нужно писать как Поле ЕСТЬ NULL, а не Поле = NULL.

Третья типовая ошибка — соединение по неиндексированным или избыточным полям и использование функций в условии связи (например, ПО РАЗНОСТЬДАТ(...) > 0). Такие условия мешают СУБД использовать индексы и резко замедляют выполнение.

Типичные ошибки
01
Отбор по полю правой таблицы в секции ГДЕ после ЛЕВОГО соединения — пропадают строки с NULL, соединение фактически становится внутренним
02
Соединение без предварительной группировки детальных данных — строки основной таблицы задваиваются, итоги завышаются
03
Сравнение «Поле = NULL» вместо «Поле ЕСТЬ NULL» — условие никогда не срабатывает
04
Отсутствие ЕСТЬNULL для числовых полей — пустые ячейки и ошибки при суммировании в отчёте
05
Соединение с виртуальной таблицей без параметров отбора — читаются лишние данные, запрос замедляется

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

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

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

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

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

Совпадает с числом строк основной таблицы (для ЛЕВОГО соединения 1:1)

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

Строк больше, чем в основной таблице — данные правой таблицы задваиваются

Значения числовых полей
Норма

Нет пустых значений, NULL заменены через ЕСТЬNULL

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

Пустые ячейки у позиций без пары

Итоговые суммы
Норма

Сумма по выборке сходится с данными исходного регистра

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

Итоги завышены кратно числу строк в присоединённой таблице

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

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

Ответы на частые вопросы

Чем ЛЕВОЕ соединение отличается от ВНУТРЕННЕГО на практике?

ЛЕВОЕ сохраняет все строки левой таблицы, подставляя NULL там, где пары нет; ВНУТРЕННЕЕ оставляет только совпавшие пары. Если вывести номенклатуру с остатками через ВНУТРЕННЕЕ, товары без движений просто исчезнут из отчёта.

Почему после соединения в отчёте задвоились строки?

Условие связи не обеспечивает уникальность: в правой таблице несколько строк на одну строку левой. Либо добавьте в условие ПО недостающие поля связи, либо предварительно сгруппируйте правую таблицу в подзапросе или временной таблице.

Как вывести ноль вместо пустого значения при ЛЕВОМ соединении?

Оберните поле в функцию ЕСТЬNULL: ЕСТЬNULL(Остатки.КоличествоОстаток, 0). Для строковых полей вторым аргументом укажите пустую строку или нужный текст-заглушку.

Можно ли соединять таблицу саму с собой?

Да, это называется самосоединением: таблица указывается дважды с разными псевдонимами. Типовой пример — поиск пар документов с одинаковым контрагентом и суммой для поиска дублей.

Что быстрее: вложенный запрос или временная таблица в соединении?

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

Почему условие «Поле = NULL» не находит записи без пары?

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

Итог

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

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