Объединение нескольких запросов в один — стандартная задача при работе с 1С:Предприятие, когда требуется получить данные из разных источников или таблиц в едином результате. Однако неопытные разработчики часто сталкиваются с ошибками синтаксиса, проблемами производительности или некорректной структурой выходных данных. В этой статье разберём все доступные способы объединения запросов в 1С 8.3 и 1С 8.2, их особенности и нюансы применения.
Основные сценарии, где это пригодится: формирование сложных отчётов, консолидация данных из разных баз, оптимизация кода для ускорения выполнения. Мы рассмотрим не только базовый синтаксис оператора ОБЪЕДИНИТЬ (UNION в SQL), но и альтернативные подходы с использованием временных таблиц, подзапросов и программного объединения результатов. Особое внимание уделим типичным ошибкам, которые приводят к дублированию строк или потере данных.
Статья будет полезна как начинающим программистам 1С, так и опытным специалистам, которые хотят систематизировать знания или найти оптимальное решение для конкретной задачи. Все примеры кода протестированы на актуальных версиях платформы и адаптированы под реальные бизнес-задачи.
1. Когда нужно объединять запросы в 1С?
Объединение запросов актуально в нескольких ключевых сценариях:
- 📊 Формирование сводных отчётов — когда данные для одного документа хранятся в разных регистрах (например, продажи и возвраты товаров).
- 🔄 Консолидация данных из нескольких баз — например, при миграции или слиянии информационных систем.
- 🔍 Поиск по нескольким таблицам — когда критерии поиска распределены по разным источникам (например, поиск клиента по имени в справочнике и по телефону в регистре сделок).
- ⚡ Оптимизация производительности — замена нескольких последовательных запросов одним сложным (уменьшает нагрузку на сервер).
Типичный пример: вам нужно получить список всех контрагентов, которые либо совершили покупку в текущем месяце (РегистрНакопления.Продажи), либо имеют задолженность (РегистрРасчётов.ДолгиКонтрагентов). Вместо двух отдельных запросов и последующего программного объединения результатов можно использовать один запрос с ОБЪЕДИНИТЬ.
Важно понимать, что объединение запросов не всегда оправдано. Если таблицы имеют разную структуру или требуется сложная постобработка данных, иногда проще выполнить несколько простых запросов и объединить результаты в коде на встроенном языке 1С. Мы вернёмся к этому в разделе про альтернативные методы.
2. Оператор ОБЪЕДИНИТЬ (UNION) — базовый синтаксис
Основной инструмент для объединения запросов в 1С — оператор ОБЪЕДИНИТЬ, который является аналогом UNION в SQL. Он позволяет "склеить" результаты нескольких запросов в одну таблицу. Главные правила:
- 📌 Одинаковая структура выборки — количество и типы полей в обоих запросах должны совпадать.
- 🔢 Порядок полей важен — первое поле первого запроса соответствует первому полю второго.
- 🚫 Дубликаты по умолчанию удаляются — если не использовать модификатор
ВСЕ.
Базовый синтаксис:
ВЫБРАТЬ
Поле1, Поле2
ИЗ
Таблица1
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Поле1, Поле2
ИЗ
Таблица2
Пример с реальными данными: объединение списка активных клиентов и потенциальных лидов из разных справочников:
ВЫБРАТЬ
Справочник.Клиенты.Наименование КАК Контрагент,
Справочник.Клиенты.ИНН КАК ИНН
ИЗ
Справочник.Клиенты КАК Клиенты
ГДЕ
Клиенты.Активный = ИСТИНА
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Справочник.Лиды.Наименование КАК Контрагент,
Справочник.Лиды.ИНН КАК ИНН
ИЗ
Справочник.Лиды КАК Лиды
ГДЕ
Лиды.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЛидов.ВРаботе)
Если в объединённых запросах есть поля с одинаковыми именами, но разным смыслом (например, "Дата" в одном запросе — дата создания, в другом — дата изменения), обязательно переименуйте их с помощью конструкции КАК, чтобы избежать путаницы в результате.
3. ОБЪЕДИНИТЬ ВСЕ vs ОБЪЕДИНИТЬ: когда использовать?
По умолчанию оператор ОБЪЕДИНИТЬ удаляет дублирующиеся строки из результата. Если вам нужно сохранить все строки, включая повторяющиеся, используйте модификатор ВСЕ:
ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2
Разница на практике:
| Метод | Поведение с дублями | Производительность | Типичное применение |
|---|---|---|---|
ОБЪЕДИНИТЬ |
Удаляет дубли | Медленнее (требует сортировки) | Отчёты без повторяющихся строк |
ОБЪЕДИНИТЬ ВСЕ |
Сохраняет все строки | Быстрее | Логирование, аудит, промежуточные данные |
Пример, где ВСЕ критично: объединение логов действий пользователей из разных сессий. Дубликаты здесь — нормальная ситуация (один и тот же пользователь мог выполнить одинаковое действие в разное время).
Важно: если вы используете ОБЪЕДИНИТЬ ВСЕ для больших таблиц, следите за объёмом результирующей выборки. В 1С есть ограничение на размер временных таблиц (зависит от настроек сервера), и при превышении лимита запрос завершится с ошибкой.
Как проверить лимит временных таблиц в 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
)
☑️ Выбор метода объединения
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. Практический пример: объединение данных из регистров
Рассмотрим реальную задачу: нужно получить список всех движений товаров (приход и расход) за месяц из регистров ТоварыНаСкладах (остатки) и ПродажиТоваров (отгрузки).
Исходные данные:
- Регистр накопления
ТоварыНаСкладахсодержит поля:Товар,Склад,Количество,Дата. - Регистр накопления
ПродажиТоваровсодержит поля:Товар,Клиент,Количество,Дата.
Решение:
ВЫБРАТЬ
ТоварыНаСкладах.Товар КАК Товар,
ТоварыНаСкладах.Склад КАК Контрагент,
ТоварыНаСкладах.Количество КАК Количество,
ТоварыНаСкладах.Дата КАК Дата,
"Приход" КАК ТипДвижения
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
ТоварыНаСкладах.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ПродажиТоваров.Товар КАК Товар,
ПродажиТоваров.Клиент КАК Контрагент,
-ПродажиТоваров.Количество КАК Количество, // Отрицательное значение для расхода
ПродажиТоваров.Дата КАК Дата,
"Расход" КАК ТипДвижения
ИЗ
РегистрНакопления.ПродажиТоваров КАК ПродажиТоваров
ГДЕ
ПродажиТоваров.Дата МЕЖДУ &НачалоМесяца И &КонецМесяца
В этом примере мы:
- Добавили поле
ТипДвижениядля идентификации источника данных. - Унифицировали названия полей (
КонтрагентвместоСклад/Клиент). - Для расхода указали отрицательное количество, чтобы потом можно было легко посчитать итоговый остаток.
Результат можно дальнейшем сгруппировать по товару и получить динамику остатков:
ВЫБРАТЬ
Товар,
СУММА(Количество) КАК ИтоговоеКоличество
ИЗ
ОбъединённыеДанные
ГРУППИРОВКА ПО
Товар
При объединении данных из регистров с разной семантикой (например, приход и расход) всегда добавляйте служебное поле для идентификации источника. Это упростит дальнейшую обработку и анализ данных.
FAQ: Частые вопросы по объединению запросов в 1С
Можно ли объединить более двух запросов?
Да, оператор ОБЪЕДИНИТЬ поддерживает цепочку из любого количества запросов. Главное — соблюдать одинаковую структуру выборки во всех подзапросах. Пример:
ВЫБРАТЬ Поле1 ИЗ Таблица1
ОБЪЕДИНИТЬ
ВЫБРАТЬ Поле1 ИЗ Таблица2
ОБЪЕДИНИТЬ
ВЫБРАТЬ Поле1 ИЗ Таблица3
Ограничение: общая длина запроса не должна превышать 20 000 символов (может варьироваться в зависимости от версии платформы).
Как объединить запросы с разными условиями отбора?
Условия отбора (ГДЕ) применяются к каждому подзапросу отдельно. Пример:
ВЫБРАТЬ Поле1 ИЗ Таблица1 ГДЕ Поле2 = 1
ОБЪЕДИНИТЬ
ВЫБРАТЬ Поле1 ИЗ Таблица2 ГДЕ Поле3 = 2
Если нужно применить общее условие ко всему результату, используйте подзапрос или временные таблицы.
Почему после объединения пропадают некоторые строки?
Скорее всего, вы используете ОБЪЕДИНИТЬ без модификатора ВСЕ, и система автоматически удаляет дубликаты. Решение:
- Добавьте
ВСЕпослеОБЪЕДИНИТЬ, если дубликаты важны. - Проверьте, нет ли в данных полей с
NULL— они могут считаться одинаковыми при сравнении.
Можно ли объединять запросы к разным базам данных?
Нет, в стандартном языке запросов 1С нельзя напрямую объединять данные из разных баз. Альтернативные решения:
- Использовать распределённые информационные базы (РИБ).
- Выгружать данные из внешней базы в временную таблицу с помощью
HTTPСервисилиCOM-Соединение. - Настроить обмен данными через XML или JSON.
Для баз на одной платформе можно использовать ВнешнийИсточникДанных (доступно в 1С:Предприятие 8.3.14+).
Как отсортировать результат объединённого запроса?
Сортировка применяется ко всему итоговому набору данных. Пример:
ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Поле1, Поле2 ИЗ Таблица2
УПОРЯДОЧИТЬ ПО Поле1
Важно: если вы используете УПОРЯДОЧИТЬ ПО в каждом подзапросе отдельно, итоговая сортировка будет применена поверх них, что может привести к неожиданному порядку строк.