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

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

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

Основные типы объединения в запросах 1С

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

Операция ОБЪЕДИНЕНИЕ (UNION) используется тогда, когда структура возвращаемых данных идентична. Представьте, что вам нужно вывести список всех контрагентов: и покупателей, и поставщиков. Они хранятся в одном справочнике, но отобраны по разным признакам. В этом случае мы просто «склеиваем» один список под другим.

В отличие от этого, СОЕДИНЕНИЕ (JOIN) применяется, когда нужно расширить информацию о строке данными из другой таблицы. Например, к документу «Реализация» нужно подтянуть наименование товара из справочника «Номенклатура». Здесь количество строк обычно не увеличивается (если связь один-к-одному), но увеличивается количество колонок.

⚠️ Внимание: При использовании оператора ОБЪЕДИНЕНИЕ количество и типы полей в верхнем и нижнем запросе должны строго совпадать. Если в первом запросе 5 колонок, а во втором 4, система выдаст ошибку синтаксиса.

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

Использование оператора ОБЪЕДИНЕНИЕ (UNION)

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

Рассмотрим классический пример: нам нужно получить список всех движений товаров за период, независимо от того, приход это или расход. Мы пишем первый запрос для регистра «ТоварыНаСкладах.Приход», а второй — для «ТоварыНаСкладах.Расход». Важно, чтобы порядок полей в ВЫБРАТЬ был идентичен.

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

💡

Используйте модификатор «ВСЕ» в операторе объединения, если знаете, что данные в выборках уникальны. Это отключает проверку на дубликаты и ускоряет формирование отчета до 30%.

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

Применение соединений: ЛЕВОЕ, ВНУТРЕННЕЕ и ПОЛНОЕ

Когда задача стоит не в сложении списков, а в обогащении данных, на сцену выходят соединения. В языке запросов 1С наиболее часто используется ЛЕВОЕ СОЕДИНЕНИЕ. Оно гарантирует, что все строки из левой таблицы (основной) попадут в результат, даже если для них не найдется соответствия в правой таблице.

В конструкторе запросов это реализуется через перетаскивание связей между таблицами. Если вы соединяете документ «ЗаказКлиента» со справочником «Контрагенты», то левая таблица — это заказы. Даже если контрагент удален или ссылка битая, строка заказа останется в отчете, а поле наименования контрагента будет пустым.

  • 🔗 Внутреннее соединение оставит в выборке только те строки, для которых есть совпадение в обеих таблицах. Используйте его для фильтрации «мусорных» записей.
  • 🔄 Полное соединение вернет все строки из обеих таблиц, заполняя пустоты нулями там, где совпадений нет. Редко используется в типовой отчетности из-за сложности интерпретации.
  • 🛡️ Левое соединение — самый безопасный вариант для основных отчетов, так как не теряет данные основного документа при отсутствии справочной информации.

Ошибки в условиях соединения — частая причина некорректных итогов. Убедитесь, что связь установлена по уникальным ключам, обычно это Ссылка или Период и Измерение для регистров. Неправильное условие может привести к эффекту «декартова произведения», когда количество строк взрывообразно растет.

☑️ Проверка условий соединения

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

Работа с временными таблицами и вложенными запросами

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

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

Использование вложенных запросов внутри оператора ИЗ также является мощным инструментом. Вы можете выполнить предварительное объединение или агрегацию данных внутри скобок, а затем работать с результатом как с обычной виртуальной таблицей. Это делает код более читаемым и модульным.

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

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

Настройка объединений в Конструкторе СКД

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

Чтобы объединить наборы, перейдите на вкладку «Наборы данных». Здесь вы можете создать новый набор, выбрав тип «Объединение наборов данных». Система предложит выбрать существующие наборы, которые будут выступать источниками. Важно сопоставить поля с одинаковым смыслом, даже если они по-разному названы в исходных запросах.

Тип операции Назначение Требования к полям Влияние на скорость
Объединение (UNION) Сложение строк Полное совпадение типов и количества Среднее (зависит от сортировки)
Левое соединение Добавление колонок Наличие общего ключа связи Высокое (при наличии индексов)
Вложенный запрос Предварительная фильтрация Корректный синтаксис SQL Зависит от сложности вложения

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

📊 Какой способ объединения вы используете чаще?
Ручное написание кода запроса
Конструктор СКД
Готовые библиотеки обработки
Комбинированный подход

Оптимизация и частые ошибки при объединении

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

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

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

Секрет быстрой работы с большими данными

Если вы объединяете данные за несколько лет, добавьте параметр «Период» в каждый подзапрос individually. Не загружайте все данные в временную таблицу, а потом фильтруйте их.

Используйте индексацию полей, участвующих в соединениях. Если вы соединяете таблицы по полю, которое не индексировано, база данных будет вынуждена выполнять полный перебор строк, что на больших объемах может «положить» сервер.

Практические примеры кода для разработчиков

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

ВЫБРАТЬ

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

ПродажиОрг1.Количество КАК Количество,

ПродажиОрг1.Сумма КАК Сумма

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

ИЗ

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

ГДЕ

ПродажиОрг1.Организация = &Организация1

ВЫБРАТЬ

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

ПродажиОрг2.Количество,

ПродажиОрг2.Сумма

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

ИЗ

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

ГДЕ

ПродажиОрг2.Организация = &Организация2

ВЫБРАТЬ

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

СУММА(ВТ_Продажи1.Количество) КАК ОбщееКоличество,

СУММА(ВТ_Продажи1.Сумма) КАК ОбщаяСумма

ИЗ

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

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

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

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

ВТ_Продажи2.Сумма

ИЗ

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

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

Номенклатура

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

⚠️ Внимание: В запросах с объединением, если вы используете агрегатные функции (СУММА, КОЛИЧЕСТВО), обязательно указывайте секцию СГРУППИРОВАТЬ ПО для всех неагрегированных полей.

Помните, что структура запроса может зависеть от версии платформы 1С:Предприятие. Новые релизы часто приносят оптимизации движка запросов, поэтому то, что тормозило в версии 8.3.10, может летать в 8.3.24. Всегда тестируйте производительность на актуальных версиях конфигурации.

💡

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

В чем разница между ОБЪЕДИНЕНИЕ и ОБЪЕДИНЕНИЕ ВСЕ?

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

Можно ли объединять наборы данных с разным количеством колонок?

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

Как объединить данные, если названия полей в разных запросах отличаются?

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

Почему мой запрос с левым соединением возвращает больше строк, чем в основной таблице?

Это происходит, если в правой таблице (справочнике или регистре) для одного ключа из левой таблицы существует несколько записей. Например, к одному документу привязано несколько записей в регистре накопления. В результате строка документа «размножается». Чтобы избежать этого, нужно предварительно агрегировать данные в правой таблице или использовать DISTINCT.

Где лучше выполнять объединение: в запросе или в коде 1С?

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