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

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

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

Разбираем, как объединить результаты двух запросов в 1С: синтаксис ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ, различия, типичные ошибки, примеры кода и проверка результата.

В языке запросов 1С для объединения результатов двух и более выборок используется конструкция ОБЪЕДИНИТЬ и её вариант ОБЪЕДИНИТЬ ВСЕ. Оба варианта складывают строки нескольких запросов в одну таблицу, но по-разному обрабатывают дубликаты: ОБЪЕДИНИТЬ удаляет повторяющиеся строки, ОБЪЕДИНИТЬ ВСЕ — сохраняет все строки без исключения.

Выбор между ними влияет не только на состав данных, но и на производительность: удаление дубликатов требует дополнительной обработки на сервере СУБД. Поэтому важно понимать, когда дедупликация действительно нужна, а когда она лишь замедляет выполнение запроса.

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

Чем ОБЪЕДИНИТЬ отличается от ОБЪЕДИНИТЬ ВСЕ

Конструкция ОБЪЕДИНИТЬ выполняет слияние выборок с устранением полностью совпадающих строк. Если одна и та же комбинация значений встречается в обоих запросах, в итоговой таблице она останется в одном экземпляре. Это удобно, когда нужен список уникальных значений, например перечень контрагентов, встречающихся хотя бы в одном из двух документов.

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

Сравнение вариантов

ОБЪЕДИНИТЬ

Удаляет дубликаты строк. Подходит для списков уникальных значений, но медленнее на больших таблицах.

ОБЪЕДИНИТЬ ВСЕ

Сохраняет все строки обеих выборок. Быстрее, но при совпадающих строках даст задвоение данных.

Практическое правило: если дальше по тексту запроса результат группируется с агрегатными функциями (СУММА, КОЛИЧЕСТВО), дубли строк важны и нужно ОБЪЕДИНИТЬ ВСЕ. Если результат используется как список ссылок без количеств — чаще подходит ОБЪЕДИНИТЬ.

Требования к объединяемым запросам

Платформа предъявляет к объединяемым выборкам строгие требования, нарушение которых приводит к ошибке ещё на этапе проверки текста запроса в конструкторе или при выполнении:

  • количество полей в каждом запросе должно совпадать;
  • порядок полей определяет соответствие — поля сопоставляются по позиции, а не по имени;
  • типы соответствующих полей должны быть совместимы (допустимо, например, объединение ссылок разных видов документов в одно поле составного типа);
  • имена полей итоговой таблицы берутся из первого запроса, поэтому осмысленные псевдонимы задают именно в нём;
  • итоги (ИТОГИ) и упорядочивание (УПОРЯДОЧИТЬ ПО) применяются к результату объединения целиком, а не к отдельным частям.

Если во втором запросе не хватает поля, его нужно добавить явно — константой или значением NULL. Например, ВЫБРАТЬ 0 КАК Количество или NULL КАК Склад. Пропуск поля — самая частая причина ошибки «Несоответствие числа полей в объединяемых запросах».

Базовый пример: остатки из двух таблиц

Типовая задача — собрать в одну таблицу данные из двух источников с одинаковой структурой. Например, остатки товаров на основном складе и на складе резерва:

ВЫБРАТЬ

Остатки.Номенклатура КАК Номенклатура,

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

ПОМЕСТИТЬ ВТ_Остатки

ИЗ

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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ

ОстаткиРезерв.Номенклатура,

ОстаткиРезерв.КоличествоОстаток

ИЗ

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

;

ВЫБРАТЬ

ВТ_Остатки.Номенклатура,

СУММА(ВТ_Остатки.Количество) КАК Количество

ИЗ

ВТ_Остатки КАК ВТ_Остатки

СГРУППИРОВАТЬ ПО

ВТ_Остатки.Номенклатура

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

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

Объединение разнородных данных: документы разных видов

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

ВЫБРАТЬ

Поступление.Ссылка КАК Документ,

Поступление.Контрагент КАК Контрагент,

Поступление.СуммаДокумента КАК Сумма,

"Поступление" КАК ВидОперации

ИЗ

Документ.ПоступлениеТоваровУслуг КАК Поступление

ГДЕ

Поступление.Проведен

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ

Реализация.Ссылка,

Реализация.Контрагент,

Реализация.СуммаДокумента,

"Реализация"

ИЗ

Документ.РеализацияТоваровУслуг КАК Реализация

ГДЕ

Реализация.Проведен

Поле «Документ» в итоговой таблице получит составной тип (ссылки на оба вида документов). Это нормально для отчётов, но затрудняет соединение с табличными частями — у них разные имена. Если нужны данные табличных частей, выбирайте их внутри каждой части объединения с приведением к общему набору колонок.

Объединение уже полученных результатов на встроенном языке

Иногда запросы уже выполнены по отдельности, и нужно слить две таблицы значений программно. Встроенного метода «объединить таблицы» нет, поэтому строки переносят циклом:

Для Каждого СтрокаТаблицы Из Таблица2 Цикл

НоваяСтрока = Таблица1.Добавить();

ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТаблицы);

КонецЦикла;

Перед переносом убедитесь, что состав и типы колонок обеих таблиц совпадают, иначе ЗаполнитьЗначенияСвойств пропустит несовпадающие поля или вызовет ошибку при несовместимости типов. При необходимости добавьте недостающие колонки методом Таблица1.Колонки.Добавить("ИмяКолонки", ОписаниеТипа).

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

Если обе выборки берутся из одной таблицы с разными отборами, часто дешевле заменить объединение одним запросом с условием ИЛИ или списком значений в В(...). Один проход по таблице обычно быстрее двух.
ПЗ
Практическое замечание

Проверка результата и типичные ошибки

После написания запроса проверьте его в консоли запросов на реальных данных, а не только на синтаксис в конструкторе. Конструктор ловит структурные ошибки, но не показывает проблемы с содержимым — задвоения, потерю строк, неверные суммы.

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

Как проверить результат

Количество строк итоговой таблицы
Норма

При ОБЪЕДИНИТЬ ВСЕ равно сумме строк обеих выборок

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

Строк меньше — возможно, случайно использовано ОБЪЕДИНИТЬ без ВСЕ

Суммы по числовым полям
Норма

Итог равен сумме итогов отдельных запросов

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

Сумма занижена — строки-дубликаты удалены дедупликацией

Типы полей результата
Норма

Поля имеют ожидаемые типы, ссылки открываются

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

Поле стало составного типа неожиданно или содержит NULL там, где их не должно быть

Типичные ошибки
01
Разный порядок полей в объединяемых запросах — данные попадают не в те колонки, ошибка может не выводиться, если типы совместимы
02
ОБЪЕДИНИТЬ вместо ОБЪЕДИНИТЬ ВСЕ при последующем суммировании — итоги занижаются из-за удаления дублей
03
Попытка упорядочить одну часть объединения — УПОРЯДОЧИТЬ ПО допустимо только после всей конструкции
04
Отбор во временной таблице после объединения вместо отборов внутри каждой части — лишнее сканирование и рост временной таблицы
05
Использование РАЗЛИЧНЫЕ вместе с ОБЪЕДИНИТЬ без необходимости — двойная дедупликация и потеря производительности

Оптимизация объединённых запросов

Главное правило производительности: отборы накладывайте внутри каждой части объединения, а не на итоговый результат. Тогда СУБД использует индексы исходных таблиц, и во временную таблицу попадает минимум строк.

Если объединение помещается во временную таблицу, а затем соединяется с другими данными, позаботьтесь об индексации: добавьте предложение ИНДЕКСИРОВАТЬ ПО после выборки во временную таблицу. Без индекса соединение больших временных таблиц выполняется полным перебором.

Порядок действий при написании объединения
  1. 1
    Определите, нужны ли дубликаты: да — ОБЪЕДИНИТЬ ВСЕ, нет — ОБЪЕДИНИТЬ
  2. 2
    Приведите обе выборки к одинаковому набору и порядку полей, недостающие поля заполните константами или NULL
  3. 3
    Задайте осмысленные псевдонимы полей в первом запросе
  4. 4
    Разместите отборы (ГДЕ) внутри каждой части объединения
  5. 5
    Проверьте результат в консоли запросов: число строк, суммы, типы полей
  6. 6
    При необходимости добавьте УПОРЯДОЧИТЬ ПО, ИТОГИ или ИНДЕКСИРОВАТЬ ПО после всей конструкции

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

Можно ли объединить больше двух запросов?

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

Как объединить запросы с разным количеством полей?

Напрямую — никак, платформа выдаст ошибку. Добавьте недостающие поля в «короткий» запрос константами (0, пустая строка, дата '00010101'), значением NULL или литералом нужного типа. Если поле в итоговой таблице вообще не нужно, удалите его из «длинного» запроса.

Почему после ОБЪЕДИНИТЬ пропали строки?

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

Можно ли применить УПОРЯДОЧИТЬ ПО к каждой части объединения отдельно?

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

Что быстрее: объединение запросом или программное слияние таблиц значений?

Объединение в тексте запроса практически всегда быстрее: работа выполняется на сервере СУБД без передачи данных на клиент и обратно. Программный перенос строк циклом оправдан только для небольших таблиц или когда один из источников вообще не является результатом запроса — например, данные из файла или внешнего сервиса.

Как объединить результаты, если типы полей не совпадают?

Приведите типы функцией ВЫРАЗИТЬ, например: ВЫРАЗИТЬ(Поле КАК СТРОКА(100)) или ВЫРАЗИТЬ(Поле КАК ЧИСЛО(15, 2)). Если поле содержит ссылки разных видов, приведение не требуется — получится составной тип, но для дальнейших соединений его лучше сузить явно.

Итог

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

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