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

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

Статья будет полезна как начинающим программистам , так и опытным специалистам, которые хотят систематизировать знания или найти оптимальное решение для конкретной задачи. Все примеры кода протестированы на актуальных версиях платформы и адаптированы под реальные бизнес-задачи.

1. Когда нужно объединять запросы в 1С?

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

  • 📊 Формирование сводных отчётов — когда данные для одного документа хранятся в разных регистрах (например, продажи и возвраты товаров).
  • 🔄 Консолидация данных из нескольких баз — например, при миграции или слиянии информационных систем.
  • 🔍 Поиск по нескольким таблицам — когда критерии поиска распределены по разным источникам (например, поиск клиента по имени в справочнике и по телефону в регистре сделок).
  • Оптимизация производительности — замена нескольких последовательных запросов одним сложным (уменьшает нагрузку на сервер).

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

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

📊 Какой метод объединения запросов вы используете чаще?
Оператор ОБЪЕДИНИТЬ
Временные таблицы
Программное объединение в коде
Подзапросы

2. Оператор ОБЪЕДИНИТЬ (UNION) — базовый синтаксис

Основной инструмент для объединения запросов в — оператор ОБЪЕДИНИТЬ, который является аналогом UNION в SQL. Он позволяет "склеить" результаты нескольких запросов в одну таблицу. Главные правила:

  • 📌 Одинаковая структура выборки — количество и типы полей в обоих запросах должны совпадать.
  • 🔢 Порядок полей важен — первое поле первого запроса соответствует первому полю второго.
  • 🚫 Дубликаты по умолчанию удаляются — если не использовать модификатор ВСЕ.

Базовый синтаксис:

ВЫБРАТЬ

Поле1, Поле2

ИЗ

Таблица1

ОБЪЕДИНИТЬ

ВЫБРАТЬ

Поле1, Поле2

ИЗ

Таблица2

Пример с реальными данными: объединение списка активных клиентов и потенциальных лидов из разных справочников:

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

Клиенты.Активный = ИСТИНА

ОБЪЕДИНИТЬ

ВЫБРАТЬ

Справочник.Лиды.Наименование КАК Контрагент,

Справочник.Лиды.ИНН КАК ИНН

ИЗ

Справочник.Лиды КАК Лиды

ГДЕ

Лиды.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЛидов.ВРаботе)

💡

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

3. ОБЪЕДИНИТЬ ВСЕ vs ОБЪЕДИНИТЬ: когда использовать?

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

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1

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

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2

Разница на практике:

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

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

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

Как проверить лимит временных таблиц в 1С?

Лимит устанавливается в файле конфигурации сервера 1С (ragent.conf или srvinfo.reg) параметром MaxTempTableSize. По умолчанию он равен 100 МБ, но может быть увеличен администратором. Для проверки текущего значения можно использовать запрос к системным таблицам или обратиться к логам сервера.

4. Объединение запросов с разной структурой

Что делать, если запросы возвращают разное количество полей или поля разных типов? В этом случае нужно привести их к единой структуре. Основные подходы:

  • 🔧 Добавление пустых полей — если во втором запросе меньше колонок, дополните их константами или NULL.
  • 📊 Преобразование типов — используйте функции приведения типов (ЧИСЛО(), СТРОКА() и т.д.).
  • 🔄 Переименование полей — чтобы имена совпадали в итоговом результате.

Пример: объединение данных о товарах (с полями Наименование, Цена) и услугах (только Наименование):

ВЫБРАТЬ

Товары.Наименование,

Товары.Цена

ИЗ

Справочник.Товары КАК Товары

ОБЪЕДИНИТЬ

ВЫБРАТЬ

Услуги.Наименование,

0 КАК Цена

ИЗ

Справочник.Услуги КАК Услуги

Для полей с несовместимыми типами (например, Дата и Строка) используйте явное приведение:

ВЫБРАТЬ

СТРОКА(Документ.Дата) КАК ДатаСтрокой

ИЗ

Документ.ЗаказКлиента КАК Документ

ОБЪЕДИНИТЬ

ВЫБРАТЬ

Справочник.События.Наименование КАК ДатаСтрокой

ИЗ

Справочник.События

💡

При объединении запросов с разной структурой всегда проверяйте итоговый результат на наличие NULL-значений или некорректных данных. Используйте конструкцию ВЫРАЗИТЬ() для безопасного приведения типов.

5. Альтернативные методы объединения данных

Оператор ОБЪЕДИНИТЬ не всегда оптимален. Рассмотрим альтернативные подходы:

5.1. Временные таблицы

Если нужно объединить результаты с последующей сложной обработкой, удобно использовать временные таблицы:

ВЫБРАТЬ Поле1, Поле2 ПОМЕСТИТЬ ВТ1 ИЗ Таблица1;

ВЫБРАТЬ Поле1, Поле2 ПОМЕСТИТЬ ВТ2 ИЗ Таблица2;

ВЫБРАТЬ * ИЗ ВТ1

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

ВЫБРАТЬ * ИЗ ВТ2

5.2. Программное объединение в коде

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

Запрос1 = Новый Запрос("ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1");

Результат1 = Запрос1.Выполнить().Выгрузить();

Запрос2 = Новый Запрос("ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2");

Результат2 = Запрос2.Выполнить().Выгрузить();

// Объединение массивов

ИтоговыйРезультат = Новый Массив();

ИтоговыйРезультат.Добавить(Результат1);

ИтоговыйРезультат.Добавить(Результат2);

5.3. Подзапросы в секции ГДЕ

Иногда вместо объединения удобно использовать подзапросы для фильтрации:

ВЫБРАТЬ Поле1, Поле2

ИЗ Таблица1

ГДЕ Поле1 В (

ВЫБРАТЬ ПолеX ИЗ Таблица2

)

☑️ Выбор метода объединения

Выполнено: 0 / 4

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

Сложные запросы с ОБЪЕДИНИТЬ могут тормозить систему. Основные способы оптимизации:

  • 🛠 Индексы — убедитесь, что поля, используемые в условиях (ГДЕ, СОЕДИНИТЬ), проиндексированы.
  • 🗑 Фильтрация на ранних этапах — применяйте условия ГДЕ к каждому подзапросу отдельно, а не к итоговому результату.
  • 📉 Ограничение выборки — используйте ПЕРВЫЕ или РАЗЛИЧНЫЕ, если не нужны все строки.

Пример оптимизированного запроса:

ВЫБРАТЬ ПЕРВЫЕ 1000

Поле1, Поле2

ИЗ

Таблица1

ГДЕ

Поле3 = &Параметр

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

ВЫБРАТЬ ПЕРВЫЕ 1000

Поле1, Поле2

ИЗ

Таблица2

ГДЕ

Поле4 = &Параметр

Критическая ошибка многих разработчиков: применение функции ВЫРАЗИТЬ() или других вычислений над полями в секции ВЫБРАТЬ объединённого запроса. Это приводит к невозможности использования индексов и резкому падению производительности. Все преобразования перенесите в отдельные подзапросы или выполните после получения результата.

💡

Для анализа производительности сложных запросов используйте ПланЗапроса.Построить(). Этот инструмент покажет, как оптимизатор 1С обрабатывает ваш запрос, и поможет выявить узкие места.

7. Типичные ошибки и как их избежать

Разберём распространённые проблемы при объединении запросов:

⚠️ Внимание: Если в объединённых запросах используются поля с типами ХранилищеЗначения или ДвоичныеДанные, результат может быть некорректным. В таких случаях лучше выполнить отдельные запросы и объединить данные программно.
  • 🔴 Несовпадение количества полей — приводит к синтаксической ошибке. Всегда проверяйте структуру выборки.
  • 🔴 Разные типы данных в одинаковых позициях — 1С попытается автоматически привести типы, что может привести к потере данных.
  • 🔴 Использование агрегатных функцийСУММА(), КОЛИЧЕСТВО() в объединённых запросах часто дают неожиданные результаты.

Пример ошибочного запроса:

// ОШИБКА: разное количество полей

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1

ОБЪЕДИНИТЬ

ВЫБРАТЬ Поле1 ИЗ Таблица2

Исправленный вариант:

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1

ОБЪЕДИНИТЬ

ВЫБРАТЬ Поле1, NULL КАК Поле2 ИЗ Таблица2

Ещё одна типичная ошибка — попытка отсортировать итоговый результат по полю, которое есть только в одном из подзапросов. В этом случае сортировка будет применена ко всему объединённому набору, что часто приводит к нелогичному порядку строк. Решение: сортируйте данные в каждом подзапросе отдельно с помощью УПОРЯДОЧИТЬ ПО.

8. Практический пример: объединение данных из регистров

Рассмотрим реальную задачу: нужно получить список всех движений товаров (приход и расход) за месяц из регистров ТоварыНаСкладах (остатки) и ПродажиТоваров (отгрузки).

Исходные данные:

  • Регистр накопления ТоварыНаСкладах содержит поля: Товар, Склад, Количество, Дата.
  • Регистр накопления ПродажиТоваров содержит поля: Товар, Клиент, Количество, Дата.

Решение:

ВЫБРАТЬ

ТоварыНаСкладах.Товар КАК Товар,

ТоварыНаСкладах.Склад КАК Контрагент,

ТоварыНаСкладах.Количество КАК Количество,

ТоварыНаСкладах.Дата КАК Дата,

"Приход" КАК ТипДвижения

ИЗ

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

ГДЕ

ТоварыНаСкладах.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца

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

ВЫБРАТЬ

ПродажиТоваров.Товар КАК Товар,

ПродажиТоваров.Клиент КАК Контрагент,

-ПродажиТоваров.Количество КАК Количество, // Отрицательное значение для расхода

ПродажиТоваров.Дата КАК Дата,

"Расход" КАК ТипДвижения

ИЗ

РегистрНакопления.ПродажиТоваров КАК ПродажиТоваров

ГДЕ

ПродажиТоваров.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца

В этом примере мы:

  1. Добавили поле ТипДвижения для идентификации источника данных.
  2. Унифицировали названия полей (Контрагент вместо Склад/Клиент).
  3. Для расхода указали отрицательное количество, чтобы потом можно было легко посчитать итоговый остаток.

Результат можно дальнейшем сгруппировать по товару и получить динамику остатков:

ВЫБРАТЬ

Товар,

СУММА(Количество) КАК ИтоговоеКоличество

ИЗ

ОбъединённыеДанные

ГРУППИРОВКА ПО

Товар

💡

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

FAQ: Частые вопросы по объединению запросов в 1С

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

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

ВЫБРАТЬ Поле1 ИЗ Таблица1

ОБЪЕДИНИТЬ

ВЫБРАТЬ Поле1 ИЗ Таблица2

ОБЪЕДИНИТЬ

ВЫБРАТЬ Поле1 ИЗ Таблица3

Ограничение: общая длина запроса не должна превышать 20 000 символов (может варьироваться в зависимости от версии платформы).

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

Условия отбора (ГДЕ) применяются к каждому подзапросу отдельно. Пример:

ВЫБРАТЬ Поле1 ИЗ Таблица1 ГДЕ Поле2 = 1

ОБЪЕДИНИТЬ

ВЫБРАТЬ Поле1 ИЗ Таблица2 ГДЕ Поле3 = 2

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

Почему после объединения пропадают некоторые строки?

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

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

Нет, в стандартном языке запросов нельзя напрямую объединять данные из разных баз. Альтернативные решения:

  • Использовать распределённые информационные базы (РИБ).
  • Выгружать данные из внешней базы в временную таблицу с помощью HTTPСервис или COM-Соединение.
  • Настроить обмен данными через XML или JSON.

Для баз на одной платформе можно использовать ВнешнийИсточникДанных (доступно в 1С:Предприятие 8.3.14+).

Как отсортировать результат объединённого запроса?

Сортировка применяется ко всему итоговому набору данных. Пример:

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1

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

ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2

УПОРЯДОЧИТЬ ПО Поле1

Важно: если вы используете УПОРЯДОЧИТЬ ПО в каждом подзапросе отдельно, итоговая сортировка будет применена поверх них, что может привести к неожиданному порядку строк.