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