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