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

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

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

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

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

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

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

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

Соединение описывается в секции ИЗ запроса. Общая структура выглядит так: сначала указывается первая таблица с псевдонимом, затем вид соединения, вторая таблица с псевдонимом и после ключевого слова ПО — условие связи.

ВЫБРАТЬ

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

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

ИЗ

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

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

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

Псевдонимы (КАК Товары, КАК Остатки) обязательны для читаемости и позволяют однозначно указывать, из какой таблицы берётся поле. Если обе таблицы содержат поле с одинаковым именем, обращение без псевдонима вызовет ошибку неоднозначности.

В условии связи после ПО допускаются составные условия через И, а также неравенства. Однако равенство по ссылочному полю — самый быстрый и предсказуемый вариант, поскольку платформа может использовать индексы.

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

Виды соединений: ЛЕВОЕ, ПРАВОЕ, ВНУТРЕННЕЕ и ПОЛНОЕ

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

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

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

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

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

Какое соединение выбрать

ВНУТРЕННЕЕ

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

ЛЕВОЕ

Основная таблица — справочник или документ, вторичная — регистр. Сохраняет все строки основной таблицы, несопоставленные поля дают NULL.

ПОЛНОЕ

Сверка двух независимых источников, где расхождения важны в обе стороны. Требует аккуратной обработки NULL с обеих сторон.

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

Условие после ПО должно однозначно сопоставлять записи. Классическая ошибка — связь по неуникальному полю, например по наименованию или коду. Если в правой таблице несколько строк удовлетворяют условию, каждая строка левой таблицы продублируется столько раз, сколько нашлось совпадений. Это приводит к «раздуванию» итогов при группировке и суммировании.

Надёжное правило: связывайте таблицы по ссылке на объект (Ссылка = Номенклатура, Ссылка = Контрагент). Ссылка гарантированно уникальна. При соединении с виртуальными таблицами регистров (Остатки, Обороты, СрезПоследних) ключ связи обычно совпадает с измерением регистра.

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

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

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

И Остатки.Склад = &Склад

Условия, ограничивающие правую таблицу (период, склад, организация), корректнее передавать в параметры виртуальной таблицы, а не в секцию ГДЕ. Условие в ГДЕ применяется уже после соединения и может отсечь строки левой таблицы, фактически превратив левое соединение во внутреннее.

Соединение с виртуальными таблицами и вложенными запросами

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

РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен) КАК Цены

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

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

Порядок построения запроса с соединением
  1. 1
    Определите основную таблицу — ту, все строки которой должны попасть в результат
  2. 2
    Выберите вид соединения: для связки справочник+регистр почти всегда ЛЕВОЕ
  3. 3
    Задайте связь по ссылочному полю через ПО, включите все измерения регистра
  4. 4
    Отборы по второй таблице перенесите в параметры виртуальной таблицы или в условие ПО
  5. 5
    Выполните запрос в консоли и проверьте: количество строк, NULL в полях, итоги по суммам

Работа с NULL и проверка результата

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

ВЫБРАТЬ

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

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

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

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

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

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

Не больше числа строк основной таблицы (при связи по уникальному ключу)

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

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

Итоги по суммовым полям
Норма

Сумма совпадает с суммой по исходной таблице регистра

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

Сумма завышена — строки задвоились из-за условия связи

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

NULL только там, где данных заведомо нет

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

NULL повсюду — условие связи не срабатывает, проверьте типы и поля

Типичные ошибки и влияние на производительность

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

Отдельная группа проблем — производительность. Соединение больших таблиц без индексируемых полей связи заставляет платформу перебирать записи. Ссылочные поля индексированы по умолчанию, поэтому связь по ссылке быстрая. А вот соединение по строковому представлению, по вычисляемому выражению или с функциями в условии ПО может работать на порядки медленнее.

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

Типичные ошибки при соединении таблиц
01
Связь по неуникальному полю (наименование, код) — строки дублируются, суммы завышаются
02
Отбор по полю правой таблицы в ГДЕ — левое соединение фактически становится внутренним, позиции теряются
03
Неполное условие связи по измерениям регистра — данные разных складов или организаций смешиваются
04
Арифметика с NULL без ЕСТЬNULL — в итоговых полях появляются пустые значения
05
Соединение полных таблиц без предварительного отбора — запрос выполняется медленно на больших базах

Когда соединение не нужно: альтернативы

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

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

Маршрут решения

Как выбрать подход

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

Частые вопросы

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

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

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

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

Можно ли соединить больше двух таблиц?

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

Как соединить таблицы по периоду, а не по ссылке?

В условии ПО допустимы неравенства, например: Документ.Дата МЕЖДУ Обороты.ПериодНачало И Обороты.ПериодКонец. Такие связи работают медленнее равенства по ссылке, поэтому по возможности ограничивайте диапазон дат параметрами виртуальной таблицы.

Что выводить вместо NULL в полях второй таблицы?

Для чисел — ЕСТЬNULL(Поле, 0), для строк — ЕСТЬNULL(Поле, ""), для ссылок значение NULL обычно оставляют, а в СКД задают оформление пустого значения. Без ЕСТЬNULL арифметика с такими полями даст NULL в итогах.

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

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

Итог

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

Соединение задаётся в секции ИЗ конструкцией «таблица ВИД СОЕДИНЕНИЕ таблица ПО условие». Связывайте таблицы по ссылке, учитывайте все измерения регистра, отборы по второй таблице переносите в параметры виртуальной таблицы, а числовые поля оборачивайте в ЕСТЬNULL. Проверяйте результат по количеству строк и контрольным суммам — это выявляет дублирование и потерю данных.