Работа с данными в 1С:Предприятие часто требует объединения результатов нескольких запросов в единую выборку. Это может понадобиться для формирования сложных отчетов, консолидации данных из разных регистров или сравнения информации по нескольким периодам. Однако стандартный язык запросов имеет свои особенности, которые отличают его от классического SQL.

В этой статье мы разберем 5 основных способов объединения запросов — от простого оператора UNION до использования временных таблиц и программного объединения результатов. Вы узнаете, когда какой метод применять, как избежать типичных ошибок при работе с большими объемами данных, и увидите практические примеры кода для каждой техники. Особое внимание уделим вопросам производительности — ведь неправильное объединение запросов может замедлить работу системы в десятки раз.

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

1. Оператор UNION: базовый способ объединения

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

  • 🔹 Количество полей в обоих запросах должно совпадать
  • 🔹 Типы соответствующих полей должны быть совместимы
  • 🔹 Порядок полей в SELECT должен быть одинаковым
  • 🔹 По умолчанию дубликаты строк удаляются (используйте UNION ALL для сохранения дублей)

Пример объединения данных о продажах из двух разных периодов:

ВЫБРАТЬ

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

Продажи.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

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

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

ВЫБРАТЬ

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

Продажи.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

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

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

📊 Какой оператор объединения вы используете чаще?
UNION
UNION ALL
Временные таблицы
Программное объединение

2. Временные таблицы: для сложных многоэтапных объединений

Когда нужно объединить результаты нескольких запросов с дополнительной обработкой, на помощь приходят временные таблицы. Они позволяют:

  • 📊 Сохранять промежуточные результаты
  • 🔄 Использовать их в последующих запросах
  • 🛠 Применять разные условия фильтрации к разным частям данных

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

// Создаем временную таблицу для первых данных

Запрос1 = Новый Запрос;

Запрос1.Текст =

"ВЫБРАТЬ

| Продажи.Контрагент КАК Контрагент,

| Продажи.СуммаДокумента КАК Сумма,

| ""Продажа"" КАК ТипДокумента

|ИЗ

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

|ГДЕ

| Продажи.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос1.УстановитьПараметр("НачалоПериода", НачалоГода(ТекущаяДата()));

Запрос1.УстановитьПараметр("КонецПериода", КонецГода(ТекущаяДата()));

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

ВременнаяТаблица1 = Результат1.Выгрузить();

// Добавляем данные второго типа

Запрос2 = Новый Запрос;

Запрос2.Текст =

"ВЫБРАТЬ

| Возвраты.Контрагент КАК Контрагент,

| -Возвраты.СуммаДокумента КАК Сумма,

| ""Возврат"" КАК ТипДокумента

|ИЗ

| Документ.ВозвратТоваровОтПокупателя КАК Возвраты

|ГДЕ

| Возвраты.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос2.УстановитьПараметр("НачалоПериода", НачалоГода(ТекущаяДата()));

Запрос2.УстановитьПараметр("КонецПериода", КонецГода(ТекущаяДата()));

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

ВременнаяТаблица2 = Результат2.Выгрузить();

// Объединяем результаты

ОбщийРезультат = Новый ТаблицаЗначений;

ОбщийРезультат.Колонки.Добавить("Контрагент");

ОбщийРезультат.Колонки.Добавить("Сумма");

ОбщийРезультат.Колонки.Добавить("ТипДокумента");

ОбщийРезультат.Очистить();

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица1, "Контрагент");

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица1, "Сумма");

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица1, "ТипДокумента");

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица2, "Контрагент");

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица2, "Сумма");

ОбщийРезультат.ЗагрузитьКолонку(ВременнаяТаблица2, "ТипДокумента");

⚠️ Внимание: При работе с большими объемами данных (более 100 000 строк) временные таблицы в памяти могут вызывать ошибки нехватки памяти. В таких случаях используйте временные таблицы в базе данных через МенеджерВременныхТаблиц.

3. Подзапросы в секции ИЗ: альтернатива UNION

Если нужно объединить данные с дополнительной фильтрацией, можно использовать подзапросы в секции ИЗ. Этот метод особенно удобен, когда:

  • 🎯 Нужно применить разные условия к разным частям данных
  • 📈 Требуется агрегировать данные перед объединением
  • 🔗 Нужно соединить результаты с другими таблицами

Пример объединения данных о продажах и платежах с последующей фильтрацией по сумме:

ВЫБРАТЬ

ОбъединенныеДанные.Контрагент,

ОбъединенныеДанные.ТипОперации,

ОбъединенныеДанные.Сумма

ИЗ

(

ВЫБРАТЬ

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

""Продажа"" КАК ТипОперации,

Продажи.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

Продажи.СуммаДокумента > 10000

ОБЪЕДИНИТЬ

ВЫБРАТЬ

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

""Платеж"" КАК ТипОперации,

Платежи.Сумма КАК Сумма

ИЗ

Документ.ПоступлениеНаРасчетныйСчет КАК Платежи

ГДЕ

Платежи.Сумма > 5000

) КАК ОбъединенныеДанные

ГДЕ

ОбъединенныеДанные.Сумма > 15000

Такой подход позволяет гибко фильтровать данные на каждом этапе, но может быть менее производительным, чем использование временных таблиц для больших выборок.

💡

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

4. Программное объединение результатов

Когда стандартные средства языка запросов не подходят (например, нужно применить сложную логику объединения), можно выполнить запросы отдельно и объединить результаты программно. Это дает максимальную гибкость, но требует аккуратного обращения с памятью.

Алгоритм программного объединения:

  1. Выполняем первый запрос, получаем результат в таблицу значений
  2. Выполняем второй запрос, получаем второй результат
  3. Создаем новую таблицу для объединенного результата
  4. Построчно добавляем данные из обеих таблиц
  5. При необходимости применяем дополнительную логику (фильтрацию, сортировку)
// Получаем первые данные

Запрос1 = Новый Запрос("

ВЫБРАТЬ

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

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

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Справочник.Номенклатура

ПО РегистрНакопления.ОстаткиТоваров.Номенклатура = Справочник.Номенклатура.Ссылка

ГДЕ

РегистрНакопления.ОстаткиТоваров.КоличествоОстаток > 0");

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

Таблица1 = Результат1.Выгрузить();

// Получаем вторые данные

Запрос2 = Новый Запрос("

ВЫБРАТЬ

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

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

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Справочник.Номенклатура

ПО РегистрНакопления.ОстаткиТоваров.Номенклатура = Справочник.Номенклатура.Ссылка

ГДЕ

РегистрНакопления.ОстаткиТоваров.КоличествоОстаток < 0");

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

Таблица2 = Результат2.Выгрузить();

// Объединяем результаты

ОбъединеннаяТаблица = Новый ТаблицаЗначений;

ОбъединеннаяТаблица.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));

ОбъединеннаяТаблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

// Добавляем данные из первой таблицы

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

НоваяСтрока = ОбъединеннаяТаблица.Добавить();

НоваяСтрока.Наименование = Строка.Наименование;

НоваяСтрока.Количество = Строка.Количество;

КонецЦикла;

// Добавляем данные из второй таблицы

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

НоваяСтрока = ОбъединеннаяТаблица.Добавить();

НоваяСтрока.Наименование = Строка.Наименование;

НоваяСтрока.Количество = Строка.Количество;

КонецЦикла;

⚠️ Внимание: При программном объединении больших таблиц (более 50 000 строк) используйте ПакетныйРежимЗаписи для ускорения обработки: ОбъединеннаяТаблица.ПакетныйРежимЗаписи = Истина; перед добавлением строк.

5. Использование конструктора запросов для визуального объединения

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

  • 🖥 Для начинающих разработчиков
  • 📊 При создании отчетов с множеством источников данных
  • 🔍 Для отладки сложных запросов

Как объединить запросы в конструкторе:

  1. Откройте конструктор запросов (Файл → Новый → Запрос)
  2. Добавьте первый источник данных и настройте его параметры
  3. Нажмите "Добавить объединение" и выберите тип (UNION или UNION ALL)
  4. Добавьте второй источник данных и настройте его
  5. При необходимости добавьте дополнительные условия или сортировку

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

Как открыть расширенный режим конструктора?

В обычном режиме конструктора нажмите кнопку "Еще" (три точки) в правом верхнем углу и выберите "Расширенный режим". Здесь доступны дополнительные настройки объединений, подзапросы и работа с временными таблицами.

Сравнение методов объединения: что выбрать?

Каждый из рассмотренных методов имеет свои плюсы и минусы. В таблице ниже приведено сравнение по ключевым критериям:

Метод Простота реализации Производительность Гибкость Когда использовать
UNION ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐ Простые объединения без дополнительной логики
Временные таблицы ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ Сложные многоэтапные объединения с промежуточной обработкой
Подзапросы ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐ Объединение с дополнительной фильтрацией или агрегацией
Программное объединение ⭐⭐ ⭐⭐⭐⭐⭐ Максимально гибкое объединение с произвольной логикой
Конструктор запросов ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ Быстрое создание и отладка запросов без ручного кодирования

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

💡

При работе с большими базами данных (более 1 млн записей) отдавайте предпочтение временным таблицам в базе данных через МенеджерВременныхТаблиц — это значительно снижает нагрузку на память.

Оптимизация производительности при объединении запросов

Неправильное объединение запросов может стать причиной замедления работы системы в десятки раз. Следующие рекомендации помогут избежать типичных ошибок:

  • 🚀 Индексируйте поля, используемые в условиях объединения и фильтрации
  • 🧹 Ограничивайте выборку с помощью РАЗЛИЧНЫЕ, ПЕРВЫЕ или условий в ГДЕ
  • 🔄 Избегайте вложенных подзапросов в секции ГДЕ — заменяйте их соединениями
  • 📊 Используйте временные таблицы для сложных многоэтапных объединений
  • 🔍 Анализируйте план выполнения запроса для выявления узких мест

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

ВЫБРАТЬ РАЗЛИЧНЫЕ

ОбъединенныеДанные.Контрагент КАК Контрагент,

СУММА(ОбъединенныеДанные.Сумма) КАК ИтоговаяСумма

ИЗ

(

ВЫБРАТЬ

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

Продажи.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

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

И Продажи.СуммаДокумента > 0

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

ВЫБРАТЬ

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

Платежи.Сумма КАК Сумма

ИЗ

Документ.ПоступлениеНаРасчетныйСчет КАК Платежи

ГДЕ

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

) КАК ОбъединенныеДанные

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

ОбъединенныеДанные.Контрагент

ИМЕЮЩИЕ

СУММА(ОбъединенныеДанные.Сумма) > 10000

Обратите внимание на использование:

  • 🔹 РАЗЛИЧНЫЕ для исключения дублей на этапе выборки
  • 🔹 Агрегирующей функции СУММА вместо пост-обработки
  • 🔹 Фильтрации по дате и сумме до объединения

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

Можно ли в 1С использовать UNION для запросов с разным количеством полей?

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

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

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

ВЫБРАТЬ

СТРОКА(Продажи.Количество) КАК КоличествоСтрокой

ИЗ ...

Или наоборот:

ВЫБРАТЬ

ЧИСЛО(Данные.ТекстовоеКоличество) КАК КоличествоЧислом

ИЗ ...

Почему при использовании UNION результаты сортируются неправильно?

Оператор UNION в 1С применяет сортировку (ПОРЯДОК ПО) ко всему объединенному результату, а не к отдельным частям. Если вам нужно отсортировать данные внутри каждой части объединения, используйте подзапросы:

ВЫБРАТЬ * ИЗ

(

ВЫБРАТЬ ... ПОРЯДОК ПО Дата УБЫВ

) КАК ПерваяЧасть

ОБЪЕДИНИТЬ

ВЫБРАТЬ * ИЗ

(

ВЫБРАТЬ ... ПОРЯДОК ПО Дата ВОЗР

) КАК ВтораяЧасть

Как объединить данные из разных баз 1С?

Для объединения данных из разных баз используйте:

  1. Распределенные информационные базы (РИБ) — для регулярного обмена
  2. COM-соединение — для однократного получения данных
  3. HTTP-сервисы — для облачных решений
  4. Выгрузка/загрузка в XML/JSON — для разовых операций

Пример получения данных через COM:

Подключение = Новый COMОбъект("V83.COMConnector");

Соединение = Подключение.Connect("File=""C:\Bases\Base2"";Usr=""Администратор""");

Запрос = Соединение.NewObject("Запрос");

Запрос.Текст = "ВЫБРАТЬ ...…";

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

Что делать, если при объединении возникает ошибка "Слишком сложный запрос"?

Эта ошибка typична для сложных запросов с множеством объединений. Решения:

  • 🔹 Разбейте запрос на несколько более простых, объедините результаты программно
  • 🔹 Используйте временные таблицы для промежуточных результатов
  • 🔹 Упростите условия в секции ГДЕ, перенесите часть логики в пост-обработку
  • 🔹 Обновите платформу — в новых версиях 1С повышен лимит сложности запросов

Также проверьте, не используете ли вы ВЫРАЗИТЬ или другие ресурсоемкие функции в условиях объединения.