Разработка сложных отчетов и механизмов выборки данных в платформе 1С:Предприятие 8 часто требует работы с несколькими источниками информации одновременно. Начинающие разработчики нередко сталкиваются с ситуацией, когда нужные данные разбросаны по разным регистрам, документам или справочникам, и возникает логический вопрос: как собрать их в единую структуру? Понимание механизмов объединения таблиц является фундаментальным навыком для любого программиста 1С, позволяющим оптимизировать код и ускорить выполнение запросов.
В языке запросов 1С существует несколько принципиально разных способов соединения данных, каждый из которых решает свои специфические задачи. Одни методы позволяют вертикально «склеить» результаты выборок, другие — горизонтально связать таблицы по ключевым полям. Неправильный выбор оператора может привести не только к логическим ошибкам в отчете, но и к существенному падению производительности системы при работе с большими объемами данных.
В этой статье мы детально разберем синтаксис и сферы применения основных операторов объединения. Вы научитесь различать ситуации, когда необходимо использовать UNION ALL, а когда требуется полноценное соединение через JOIN. Мы также рассмотрим нюансы работы с временными таблицами и особенности оптимизации таких запросов сервером 1С.
Вертикальное объединение результатов с помощью UNION
Оператор UNION предназначен для объединения результатов нескольких запросов в один итоговый набор записей. Это так называемое вертикальное объединение, где строки одного запроса добавляются под строками другого. Ключевое требование здесь — строгое соответствие структуры: количество полей в выбираемых списках должно быть одинаковым, а их типы данных должны быть совместимы.
Существует две модификации этого оператора: UNION и UNION ALL. Разница между ними критична для производительности. Первый вариант автоматически удаляет дублирующиеся строки из итогового результата, что требует дополнительных вычислительных ресурсов сервера для сортировки и сравнения. Второй вариант просто собирает все строки вместе, игнорируя повторения, что работает значительно быстрее.
⚠️ Внимание: При использовании обычногоUNIONсервер 1С выполняет неявную сортировку для поиска дублей. Если вам не нужно удалять повторяющиеся строки, всегда используйтеUNION ALLдля ускорения выполнения запроса.
Рассмотрим типичный сценарий, когда необходимо вывести список номенклатуры из двух разных справочников или выборок.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Услуги.Ссылка,
Услуги.Наименование
ИЗ
Справочник.Услуги КАК Услуги
ГДЕ
Услуги.ЭтоГруппа = ЛОЖЬ
Такой подход часто используется при формировании сводных отчетов, где данные поступают из разнородных источников, но должны быть отображены в единой таблице. Если типы полей не совпадают, система выдаст ошибку компиляции запроса, поэтому необходимо явно приводить типы или использовать пустые значения.
Горизонтальное соединение таблиц через JOIN
В отличие от вертикального сложения строк, операторы группы JOIN позволяют соединять таблицы по горизонтали, добавляя новые колонки к существующим записям на основе условия связи. Это основной инструмент для работы с реляционными данными, когда информация о сущности разбросана по разным таблицам базы данных.
В языке запросов 1С поддерживаются различные виды соединений, каждое из которых определяет логику попадания записей в выборку. Внутреннее соединение (INNER JOIN) оставляет только те строки, для которых есть соответствие в обеих таблицах. Если связи нет, запись исключается из результата полностью.
Чаще всего в практике разработчика возникает потребность получить все записи из основной таблицы и подтянуть данные из связанной, даже если связь отсутствует. Для этого используется LEFT JOIN (левое соединение). В этом случае все строки из левой таблицы попадут в выборку, а поля из правой таблицы будут заполнены значениями NULL (или ПУСТО), если пара не найдена.
При построении сложных запросов с несколькими соединениями старайтесь размещать таблицы с наибольшим количеством отбираемых записей слева, а таблицы-справочники или регистры — справа. Это помогает оптимизатору запросов 1С построить более эффективный план выполнения.
Синтаксис соединения требует указания условия связи в блоке ПО. Обычно это равенство ссылок или ключевых полей. Ошибки в условии соединения могут привести к декартовому произведению, когда каждая строка одной таблицы умножается на каждую строку другой, вызывая катастрофический рост времени выполнения.
ВЫБРАТЬ
Документ.Ссылка,
Документ.Дата,
Контрагент.Наименование КАК Партнер
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагент
ПО Документ.Контрагент = Контрагент.Ссылка
ГДЕ
Документ.Проведен = ИСТИНА
Использование правильных типов соединений напрямую влияет на читаемость кода и логику работы отчета. Понимание разницы между внутренним и внешним соединением позволяет избегать ситуаций, когда из выборки неожиданно «пропадают» документы из-за отсутствия заполненного поля в связанной таблице.
Сравнение типов соединений и их влияние на выборку
Выбор конкретного типа соединения зависит от бизнес-логики задачи. Иногда требуется найти только полные совпадения, а иногда — выявитьющие данные. Для наглядности рассмотрим основные различия в поведении операторов при работе с двумя таблицами: основной (Левая) и связанной (Правая).
| Тип соединения | Записи из левой таблицы | Записи из правой таблицы | Результат при отсутствии связи |
|---|---|---|---|
| ВНУТРЕННЕЕ (INNER) | Только при наличии связи | Только при наличии связи | Запись исключается |
| ЛЕВОЕ (LEFT) | Все записи | Только при наличии связи | Поля правой таблицы = NULL |
| ПОЛНОЕ (FULL) | Все записи | Все записи | Отсутствующие поля = NULL |
Особого внимания заслуживает ПОЛНОЕ СОЕДИНЕНИЕ (FULL JOIN). Оно объединяет результаты левого и правого соединения, возвращая все записи из обеих таблиц. Это полезно при сверке данных, когда нужно увидеть расхождения в обоих направлениях одновременно.
Также существует ПРАВОЕ СОЕДИНЕНИЕ (RIGHT JOIN), которое зеркально отражает логику левого соединения, сохраняя все записи из правой таблицы. На практике его используют редко, так как тот же результат можно получить, просто поменяв таблицы местами и применив LEFT JOIN.
⚠️ Внимание: При использовании соединений следите за тем, чтобы поля, участвующие в условии ПО, были проиндексированы в базе данных. Отсутствие индексов на полях соединения может замедлить выполнение запроса в десятки раз.
Операции пересечения и разности множеств
Помимо классических объединений и соединений, язык запросов 1С поддерживает теоретико-множественные операции: ПЕРЕСЕЧЕНИЕ (INTERSECT) и РАЗНОСТЬ (EXCEPT). Эти инструменты позволяют работать с результатами запросов как с математическими множествами, отфильтровывая данные на основе их присутствия или отсутствия в другой выборке.
Оператор ПЕРЕСЕЧЕНИЕ возвращает только те строки, которые присутствуют одновременно и в первом, и во втором запросе. Это аналог внутреннего соединения, но работающий со всеми полями строки целиком, а не по ключевому условию. Структура запросов также должна быть идентичной.
Оператор РАЗНОСТЬ вычитает из результата первого запроса все строки, которые встречаются во втором запросе. Это мощный инструмент для поиска «потерянных» или «новых» записей. Например, с его помощью можно легко найти документы, которые проведены, но не имеют движений по регистрам.
Пример использования РАЗНОСТИ
Вы можете использовать РАЗНОСТЬ для поиска номенклатуры, которая есть в остатках на складе, но не была продана за текущий месяц. Первый запрос выбирает все остатки, второй — все проданные товары, а разность покажет неликвиды.
Они менее гибки, чем JOIN, но иногда позволяют написать более лаконичный и понятный код для специфических задач сравнения списков.
Работа с временными таблицами при объединении
При построении сложных аналитических отчетов часто возникает необходимость объединять данные из более чем двух источников или выполнять промежуточные вычисления перед финальным соединением. В таких случаях на помощь приходят временные таблицы. Они позволяют разбить сложный запрос на логические этапы и сохранить промежуточные результаты в памяти сервера.
Использование временных таблиц упрощает отладку и чтение кода. Вы можете сначала сформировать выборку из одного регистра, поместить её во временную таблицу, затем подготовить данные из другого источника и уже в финальном запросе объединить их. Это особенно актуально, когда условия отбора или вычисляемые поля сложны для восприятия в одном длинном тексте запроса.
☑️ Оптимизация работы с временными таблицами
Синтаксис работы с временными таблицами включает ключевые слова ПОМЕСТИТЬ и обращение к таблице через символ #. При объединении данных из временных таблиц действуют те же правила совместимости полей, что и при работе с обычными таблицами базы данных.
ПОМЕСТИТЬ ВТ_Продажи
ВЫБРАТЬ
Продажи.Номенклатура,
СУММА(Продажи.Количество) КАК Количество
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Период МЕЖДУ &НачПериода И &КонПериода
ГРУППИРОВАТЬ ПО
Продажи.Номенклатура
ВЫБРАТЬ
Остатки.Номенклатура,
ВТ_Продажи.Количество
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Продажи
ПО Остатки.Номенклатура = ВТ_Продажи.Номенклатура
Правильное использование временных таблиц может значительно снизить нагрузку на СУБД, так как позволяет выполнять сложные фильтрации и группировки один раз, а затем многократно использовать подготовленный набор данных в различных соединениях.
Частые ошибки и оптимизация производительности
Объединение таблиц — это операция, которая при некорректном использовании может стать «узким горлышком» производительности системы. Самая распространенная ошибка — использование UNION вместо UNION ALL там, где удаление дублей не требуется. Лишняя сортировка больших массивов данных может замедлить отчет на порядки.
Еще одна критичная проблема — соединение таблиц по неиндексируемым полям или полям с разными типами данных, требующими неявного преобразования. Сервер 1С вынужден выполнять полные сканирования таблиц, что недопустимо в высоконагруженных системах. Всегда проверяйте, что поля в условии ПО имеют одинаковый тип и структуру.
⚠️ Внимание: Избегайте использования функций в условии соединения (например, ПО ЛЕВЫЙ(Таблица1.Поле, 5) = Таблица2.Поле). Это полностью отключает использование индексов и приводит к перебору всех записей.
Также стоит упомянуть о порядке таблиц в соединении. Хотя современный оптимизатор запросов 1С достаточно умен, чтобы самостоятельно определить лучший план выполнения, явное указание маленькой таблицы слева, а большой справа (при левом соединении) иногда помогает подсказать системе верное направление обработки данных.
Главный принцип оптимизации: минимизируйте количество обрабатываемых строк до этапа соединения. Используйте отборы в каждом подзапросе перед объединением, а не только в финальном запросе.
Регулярный анализ планов выполнения запросов через консоль запросов или технологический журнал позволяет выявлять проблемные места в логике объединения. Обращайте внимание на операции «Слияние» (Merge Join) и «Вложенные циклы» (Nested Loops) — их наличие не всегда является ошибкой, но требует понимания контекста.
В чем разница между UNION и UNION ALL?
Оператор UNION автоматически удаляет дублирующиеся строки из результата, выполняя дополнительную сортировку и сравнение. UNION ALL просто объединяет все строки без проверки на уникальность, что работает значительно быстрее. Используйте UNION ALL, если дубли не влияют на логику отчета.
Что вернет запрос, если использовать LEFT JOIN и в правой таблице нет совпадений?
При использовании ЛЕВОЕ СОЕДИНЕНИЕ все записи из левой таблицы попадут в результат. Для тех строк, где не нашлось пары в правой таблице, поля из правой таблицы будут заполнены значением NULL (пусто).
Можно ли объединять таблицы из разных информационных баз в одном запросе?
Нет, стандартный язык запросов 1С работает только в контексте одной информационной базы. Для объединения данных из разных баз необходимо использовать механизмы внешней обработки, COM-соединение или выгрузку данных во временные таблицы одной из баз.
Как объединить более двух таблиц?
Вы можете последовательно добавлять операторы ОБЪЕДИНИТЬ ВСЕ или ЛЕВОЕ СОЕДИНЕНИЕ. Для UNION просто продолжайте цепочку запросов. Для JOIN добавляйте новые блоки СОЕДИНЕНИЕ.. ПО после предыдущей таблицы в блоке ИЗ.
Почему запрос с объединением работает медленно?
Причины могут быть разными: отсутствие индексов на полях соединения, использование функций в условиях, выборка лишних полей, отсутствие отборов до объединения или использование UNION вместо UNION ALL. Проверьте план выполнения запроса для точной диагностики.