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

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

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

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

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

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

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

Два способа объединения: чем они отличаются

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

Пакетный запрос — это несколько независимых операторов ВЫБРАТЬ в одном тексте запроса, разделённых точкой с запятой. Каждый оператор может создавать временную таблицу (конструкция ПОМЕСТИТЬ), которую используют следующие операторы. Метод ВыполнитьПакет() возвращает массив результатов, а Выполнить() — результат только последнего оператора.

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

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

Склейка однородных выборок в одну таблицу. Быстро, сохраняет дубли. Подходит для объединения оборотов из разных регистров.

ОБЪЕДИНИТЬ

То же, но с удалением дублей строк. Медленнее из-за дополнительной обработки. Нужен, только если дубли реально возможны и недопустимы.

Пакетный запрос с временными таблицами

Последовательная логика: отбор, фильтрация, итоговая выборка. Подходит для сложных отчётов, где данные готовятся поэтапно.

Соединение (СОЕДИНЕНИЕ)

Не объединение строк, а склейка колонок по ключу. Используйте, когда нужно дополнить одни данные другими, а не сложить их.

Как объединить выборки через ОБЪЕДИНИТЬ ВСЕ

Типовая задача — собрать в одну таблицу данные из разных регистров, например поступления и списания товаров. Каждая часть объединения должна возвращать одинаковый набор полей в одинаковом порядке. Если в какой-то части поля нет, подставьте значение-заглушку: NULL, 0 или пустую строку с явным приведением типа через ВЫРАЗИТЬ.

ВЫБРАТЬ

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

Поступления.Количество КАК Количество,

"Поступление" КАК ВидДвижения

ИЗ

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

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

ВЫБРАТЬ

Расходы.Номенклатура,

-Расходы.Количество,

"Расход"

ИЗ

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

Псевдонимы полей задаются только в первой части объединения — именно они попадут в результат. Поле-маркер вроде «ВидДвижения» помогает потом различать строки из разных источников и строить по ним группировки или отборы в СКД.

Если типы полей не совпадают — например, в одной части ссылка на справочник, а в другой строка, — платформа выдаст ошибку несовместимости типов. Лечится это приведением: ВЫРАЗИТЬ(Поле КАК Строка(100)) или заменой на NULL с последующим ЕСТЬNULL в вышестоящей логике.

Пакетный запрос: несколько операторов в одном тексте

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

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

СУММА(Продажи.Количество) КАК Количество

ПОМЕСТИТЬ ВТ_Продажи

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

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

Продажи.Номенклатура

;

ВЫБРАТЬ

ВТ_Продажи.Номенклатура КАК Номенклатура,

ВТ_Продажи.Количество КАК Количество,

Спр.Артикул КАК Артикул

ИЗ

ВТ_Продажи КАК ВТ_Продажи

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

ПО ВТ_Продажи.Номенклатура = Спр.Ссылка

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

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

Практические сценарии и уточнения

Объединение с итогами и группировкой

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

Объединение запроса с таблицей значений

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

Пакетный запрос в СКД

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

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

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

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

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

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

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

Число строк результата
Норма

Равно сумме строк отдельных выборок (для ОБЪЕДИНИТЬ ВСЕ)

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

Строк меньше или больше — проверяйте отборы и соединения в частях

Контрольная сумма по числовому полю
Норма

Совпадает с суммой итогов исходных запросов

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

Расхождение — ищите размножение строк через соединение или потерю строк

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

Соответствуют ожиданиям, нет нежелательных составных типов

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

Появился составной тип или NULL там, где ожидалось значение

Временные таблицы пакета
Норма

Содержат ожидаемые данные на каждом шаге (проверка в консоли)

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

Таблица пуста или недоступна — проверяйте ПОМЕСТИТЬ и менеджер таблиц

Производительность и ограничения

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

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

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

Можно ли объединить больше двух запросов через ОБЪЕДИНИТЬ?

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

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

ОБЪЕДИНИТЬ складывает строки друг под другом — набор колонок не меняется, растёт количество строк. СОЕДИНЕНИЕ склеивает таблицы по ключу горизонтально — колонки добавляются, а строки сопоставляются. Для задачи «продажи и возвраты одним списком» нужно объединение, для задачи «к продажам добавить артикул из справочника» — соединение.

Почему запрос с ОБЪЕДИНИТЬ выдаёт ошибку несовместимости типов?

Потому что одноимённые по позиции поля в разных частях имеют разные типы — например, ссылка на разные справочники или число и строка. Приведите поле к общему типу через ВЫРАЗИТЬ или подставьте NULL. Если ссылки разных справочников объединяются намеренно, платформа сама создаст составной тип, но это может замедлить запрос.

Как получить результаты всех операторов пакетного запроса?

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

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

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

Что быстрее: один пакетный запрос или три отдельных?

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

Итог

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

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