Объединение запросов в 1С: от ОБЪЕДИНИТЬ до виртуальных таблиц
Содержание
Оператор ОБЪЕДИНИТЬ складывает строки нескольких выборок в один результат по вертикали, а ОБЪЕДИНИТЬ ВСЕ делает то же самое, но не убирает дубликаты и работает быстрее. Если же вам нужно не добавить строки, а подтянуть столбцы из связанной таблицы — это уже не объединение, а СОЕДИНЕНИЕ. Эти два слова в русскоязычном 1С часто путают, хотя задачи у них противоположные.
Ниже разберём объединение запросов на конкретных примерах кода: синтаксис ОБЪЕДИНИТЬ, правила по столбцам, временные и виртуальные таблицы для оптимизации, соединение таблиц как альтернативу и отдельный случай — склейку данных из разных информационных баз. Весь код — для платформы 8.3, язык запросов одинаков в тонком клиенте, сервере и внешних обработках.
Объединение и соединение: в чём разница
Прежде чем писать код, определитесь, что именно нужно получить. От этого зависит выбор оператора.
- 🔼 Объединение (
ОБЪЕДИНИТЬ) — строки второй выборки дописываются под строки первой. Число столбцов у всех частей совпадает, результат растёт в высоту. - ◀️▶️ Соединение (
СОЕДИНЕНИЕ) — к строкам одной таблицы сбоку добавляются поля другой по условию связи. Результат растёт в ширину.
Простой ориентир: нужно собрать однотипные данные из нескольких источников в один список (приходы и расходы, товары и услуги, несколько документов) — берите объединение. Нужно к номенклатуре добавить цену , остаток или реквизит из другой таблицы — берите соединение.
ОБЪЕДИНИТЬ ВСЕ, если дубли невозможны или не мешают; ОБЪЕДИНИТЬ, если полные дубли строк надо убрать.ЛЕВОЕ СОЕДИНЕНИЕ, чтобы сохранить все строки основной таблицы.ПОМЕСТИТЬ, затем обращение к ней по имени.ТаблицаЗначений в параметр запроса или внешний источник данных.ОБЪЕДИНИТЬ и ОБЪЕДИНИТЬ ВСЕ: синтаксис и правила
Классический пример — собрать движения товара в одну таблицу: приходы из одного документа, расходы из другого. Приход кладём в столбец «Приход», расход — в «Расход», недостающую величину заполняем нулём.
ВЫБРАТЬ
Поступление.Номенклатура КАК Номенклатура,
Поступление.Количество КАК Приход,
0 КАК Расход
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК Поступление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Реализация.Номенклатура,
0,
Реализация.Количество
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Реализация
Разберём правила, которые нарушают чаще всего:
- Число столбцов во всех частях одинаково. Если в первой выборке три поля, во второй тоже должно быть три. Иначе платформа выдаст ошибку о несовпадении количества колонок.
- Имена берутся из первой выборки. Псевдонимы (
КАК Номенклатура,КАК Приход) во второй и последующих частях можно не писать — колонки сопоставляются по порядку, а не по названию. - Типы объединяются. Если в одной части столбец числовой, а в другой строковый, результат получит составной тип. Следите, чтобы
0и реквизитКоличествобыли одного типа — здесь оба числовые, всё в порядке. УПОРЯДОЧИТЬ ПОиИТОГИ— в самом конце. Они относятся ко всему объединённому результату, а не к отдельной части, и пишутся после последней выборки.
ОБЪЕДИНИТЬ без слова ВСЕ прогоняет результат через удаление полных дубликатов строк — это дополнительная сортировка и сравнение. Если вы точно знаете, что одинаковых строк не будет (например, объединяете приходы и расходы — они не пересекаются), пишите ОБЪЕДИНИТЬ ВСЕ. На больших выборках разница в скорости заметна.
Выбирайте ОБЪЕДИНИТЬ только тогда, когда дубли действительно нужно схлопнуть; в остальных случаях ОБЪЕДИНИТЬ ВСЕ быстрее и не искажает суммы при последующей группировке.
Типовой приём — объединить разнородные движения, а потом свернуть их группировкой. Результат объединения оборачивают во вложенный запрос или временную таблицу и считают итог по номенклатуре:
ВЫБРАТЬ
Движения.Номенклатура КАК Номенклатура,
СУММА(Движения.Приход) КАК Приход,
СУММА(Движения.Расход) КАК Расход
ИЗ
(ВЫБРАТЬ
Поступление.Номенклатура КАК Номенклатура,
Поступление.Количество КАК Приход,
0 КАК Расход
ИЗ
Документ.ПоступлениеТоваровУслуг.Товары КАК Поступление
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Реализация.Номенклатура,
0,
Реализация.Количество
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Реализация) КАК Движения
СГРУППИРОВАТЬ ПО
Движения.Номенклатура
Так из двух документов получается единая ведомость: приход и расход по каждой позиции в соседних столбцах. Сортировку всего набора задают через УПОРЯДОЧИТЬ ПО в самом конце — она применяется к результату целиком, а не к отдельной выборке.
Временные таблицы: разбиваем сложный запрос на части
Когда в одном запросе сходятся несколько источников, а промежуточный результат нужен повторно, его выносят во временную таблицу оператором ПОМЕСТИТЬ. Это основной приём оптимизации в 1С.
Временная таблица живёт в рамках менеджера временных таблиц. В коде его нужно создать и назначить запросу:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Сам пакетный запрос разделяется точкой с запятой. Сначала наполняем таблицу, затем обращаемся к ней по имени:
ВЫБРАТЬ
Заказы.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВыбраннаяНоменклатура
ИЗ
Документ.ЗаказПокупателя.Товары КАК Заказы
ГДЕ
Заказы.Ссылка = &Заказ
ИНДЕКСИРОВАТЬ ПО
Номенклатура
;
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
Остатки.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(
,
Номенклатура В (ВЫБРАТЬ Т.Номенклатура ИЗ ВыбраннаяНоменклатура КАК Т)
) КАК Остатки
Зачем это нужно:
- 📦 Промежуточный набор материализуется один раз, а используется в нескольких местах пакета.
- ⚡ Временную таблицу можно проиндексировать (
ИНДЕКСИРОВАТЬ ПО), и отбор по ней идёт быстрее, чем по вложенному подзапросу. - 🧩 Сложный запрос с кучей соединений разбивается на понятные шаги — его проще читать и отлаживать.
Платформа и СУБД плохо оптимизируют соединение таблицы с вложенным подзапросом или виртуальной таблицей напрямую. Если видите соединение с конструкцией (ВЫБРАТЬ ...) внутри — почти всегда это кандидат на вынос во временную таблицу.
Виртуальные таблицы: переносите отбор внутрь
Виртуальные таблицы — это Остатки, Обороты, ОстаткиИОбороты у регистров накопления, СрезПоследних и СрезПервых у регистров сведений, ОстаткиИОбороты у регистра бухгалтерии. Платформа строит их на лету, и ключевой приём оптимизации здесь — передавать условия внутрь скобок виртуальной таблицы, а не отбирать результат потом через ГДЕ.
Сравните два подхода. Медленный — сначала берём все остатки, потом фильтруем:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ГДЕ
Остатки.Склад = &Склад
Быстрый — отбор задан параметром виртуальной таблицы, и платформа отфильтрует данные ещё на уровне СУБД:
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.КоличествоОстаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки
Разница в том, что во втором случае отбор уходит в расчёт виртуальной таблицы, и промежуточный объём данных меньше. На регистре с миллионами записей это десятки раз по скорости.
Если условие отбора — это целый список значений, подайте его из временной таблицы, как в примере выше: Номенклатура В (ВЫБРАТЬ ... ИЗ ВремТаблица). Передавать внутрь можно и период, и условие одновременно — первый параметр Остатки отвечает за момент времени, второй за условие отбора:
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад)
Для СрезПоследних и СрезПервых регистра сведений первый параметр — дата среза, второй — отбор. Пустое место на позиции параметра (как (, Склад = &Склад)) означает «без отбора по этому аргументу»: запятую оставляют, значение опускают.
Соединение таблиц как альтернатива объединению
Когда задача — не сложить строки, а дополнить их полями из другой таблицы, объединение не подходит. Нужен СОЕДИНЕНИЕ. Чаще всего используют ЛЕВОЕ СОЕДИНЕНИЕ: оно сохраняет все строки левой таблицы, а недостающие поля из правой заполняет NULL.
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(Цены.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ) КАК Цены
ПО Товары.Ссылка = Цены.Номенклатура
Здесь каждому товару приписывается последняя цена. Функция ЕСТЬNULL(Цены.Цена, 0) подставляет ноль там, где цена не задана, — иначе в этих строках окажется NULL, который сломает дальнейшие вычисления.
Виды соединений в языке запросов:
| Соединение | Какие строки остаются |
|---|---|
ВНУТРЕННЕЕ | только те, что есть в обеих таблицах |
ЛЕВОЕ | все строки левой таблицы + совпавшие из правой |
ПРАВОЕ | все строки правой + совпавшие из левой |
ПОЛНОЕ | все строки обеих таблиц |
На практике ПРАВОЕ СОЕДИНЕНИЕ почти не нужно — его всегда можно переписать как левое, поменяв таблицы местами, и запрос станет читабельнее.
Данные из разных информационных баз
Язык запросов 1С работает в пределах одной информационной базы. Напрямую соединить таблицу из рабочей базы с таблицей из другой базы одним запросом нельзя. Есть два рабочих пути.
Через таблицу значений. Данные из второй базы получают отдельно (например, по COM-соединению, через веб-сервис или план обмена), складывают в ТаблицаЗначений и передают в запрос параметром. Колонки таблицы значений обязательно должны иметь объявленные типы.
ВЫБРАТЬ
ВнешниеДанные.Код КАК Код,
ВнешниеДанные.Сумма КАК Сумма
ПОМЕСТИТЬ ДанныеИзДругойБазы
ИЗ
&ТаблицаЗначений КАК ВнешниеДанные
В коде: Запрос.УстановитьПараметр("ТаблицаЗначений", ТЗ);. После этого временную таблицу ДанныеИзДругойБазы объединяют или соединяют с данными текущей базы как обычно.
Через внешний источник данных. Если вторая база — это SQL-сервер или другая СУБД, в конфигурацию добавляют объект «Внешний источник данных», описывают нужные таблицы, и тогда к ним можно обращаться прямо в запросе наряду со штатными. Этот способ тяжелее по настройке, но работает без выгрузки данных в память.
Если обе базы — это базы 1С и обмен между ними уже настроен, часто проще не строить кросс-базовый запрос, а переносить данные штатным планом обмена и работать с ними уже в одной базе.
Замер производительности и отладка запросов
Прежде чем оптимизировать, измерьте. «На глаз» ускорять запрос — верный способ потратить время впустую.
- Замер производительности в конфигураторе: меню
Отладка → Замер производительности. Запускаете сценарий, останавливаете — платформа покажет, сколько заняла каждая строка кода и каждый вызов запроса. - Консоль запросов — обработка для отладки текста запроса без встройки в код: меняете текст, прогоняете, смотрите результат и время. Консоль есть в составе типовых инструментов разработчика.
- Технологический журнал и план запроса в СУБД. Для тяжёлых случаев смотрят, какой SQL платформа отправила серверу и как он выполнился. Это уже уровень администратора базы данных.
Чек-лист оптимизации, когда объединённый или сложный запрос тормозит:
Самая частая причина тормозов — не объединение само по себе, а соединение с подзапросом или виртуальной таблицей и отбор через ГДЕ вместо параметров. Объединение строк из нескольких документов обычно дёшево.
Частые вопросы
Чем `ОБЪЕДИНИТЬ` отличается от `ОБЪЕДИНИТЬ ВСЕ`?
ОБЪЕДИНИТЬ убирает полностью одинаковые строки из результата, ОБЪЕДИНИТЬ ВСЕ оставляет все строки как есть. Второй вариант быстрее, потому что не тратит ресурсы на поиск и удаление дублей. Используйте ОБЪЕДИНИТЬ только когда дубли реально нужно схлопнуть.Почему при объединении сбиваются имена колонок?
КАК именно в первой части запроса.Можно ли объединить запросы с разным числом столбцов?
0 для числа, "" для строки или ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) для ссылки.