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