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