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

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

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

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

Временные таблицы в запросах 1С используются для промежуточной подготовки данных: отборов, группировок и расчётов перед финальной выборкой. Когда данные собраны в двух отдельных временных таблицах, возникает задача объединить их в одну — либо «вертикально» (добавить строки одной таблицы к другой), либо «горизонтально» (дополнить строки колонками по ключу). Это принципиально разные операции, и выбор между ними определяет результат.

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

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

Два смысла слова «объединить»: строки или колонки

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

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

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

Маршрут решения

Как выбрать способ

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

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

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

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

ВЫБРАТЬ

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

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

ПОМЕСТИТЬ ВТ_Итог

ИЗ

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

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

ВЫБРАТЬ

ВТ_Возвраты.Номенклатура,

ВТ_Возвраты.Количество

ИЗ

ВТ_Возвраты КАК ВТ_Возвраты

Если в какой-то выборке не хватает колонки, подставьте константу или NULL: ВЫБРАТЬ Таб.Товар, 0 КАК Сумма. Если типы не совпадают, приведите их функцией ВЫРАЗИТЬ(... КАК ЧИСЛО(15,2)). Результат объединения можно поместить в новую временную таблицу и использовать дальше в пакете запроса.

Горизонтальное объединение через СОЕДИНЕНИЕ

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

ВЫБРАТЬ

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

Остатки.КоличествоОстаток КАК Остаток,

ЕСТЬNULL(Цены.Цена, 0) КАК Цена

ИЗ

ВТ_Остатки КАК Остатки

ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Цены КАК Цены

ПО Остатки.Номенклатура = Цены.Номенклатура

ВНУТРЕННЕЕ СОЕДИНЕНИЕ оставит только строки, для которых пара нашлась в обеих таблицах. ПОЛНОЕ СОЕДИНЕНИЕ вернёт все строки обеих таблиц, дополняя NULL-ами отсутствующие стороны. Выбор зависит от того, потеря каких строк недопустима в итоговом отчёте.

Ключевой момент — уникальность ключа в присоединяемой таблице. Если в ВТ_Цены окажется две строки по одному товару, строка остатков задвоится, и итоги по количеству «поедут». При неуверенности в уникальности предварительно сгруппируйте присоединяемую таблицу.

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

Ниже — сквозной пример: две временные таблицы создаются отдельными запросами пакета, а затем объединяются в третьем. Такой пакет выполняется одним вызовом Запрос.Выполнить() через менеджер временных таблиц.

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

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

"ВЫБРАТЬ

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

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

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

|ИЗ

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

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

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

|;

|////////////////////////////////////////////////////////////

|ВЫБРАТЬ

| Закупки.Номенклатура КАК Номенклатура,

| СУММА(Закупки.КоличествоОборот) КАК Количество

|ПОМЕСТИТЬ ВТ_Закупки

|ИЗ

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

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

| Закупки.Номенклатура

|;

|////////////////////////////////////////////////////////////

|ВЫБРАТЬ

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

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

| 0 КАК Закуплено

|ИЗ

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

|

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

|

|ВЫБРАТЬ

| ВТ_Закупки.Номенклатура,

| 0,

| ВТ_Закупки.Количество

|ИЗ

| ВТ_Закупки КАК ВТ_Закупки

|ИТОГИ

| СУММА(Продано),

| СУММА(Закуплено)

|ПО

| Номенклатура";

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

Обратите внимание: чтобы свести продажи и закупки в одну строку по товару, после объединения применена группировка через ИТОГИ ПО. Альтернатива — сначала объединить в новую временную таблицу, а затем выполнить четвёртый запрос с СГРУППИРОВАТЬ ПО и суммированием. Это нагляднее и проще отлаживать.

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

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

Самый надёжный способ — отладчик. Установите точку останова после выполнения запроса и посмотрите содержимое временных таблиц через МенеджерВременныхТаблиц: выполните вспомогательный запрос ВЫБРАТЬ * ИЗ ВТ_Продажи в том же менеджере, чтобы увидеть данные до объединения.

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

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

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

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

Число строк после ОБЪЕДИНИТЬ ВСЕ
Норма

Равно сумме строк обеих таблиц

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

Строк меньше — вероятно, использован ОБЪЕДИНИТЬ без ВСЕ и дубли удалены

Число строк после ЛЕВОГО СОЕДИНЕНИЯ
Норма

Равно числу строк левой таблицы

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

Строк больше — ключ в правой таблице не уникален, данные задвоены

Значения присоединённых колонок
Норма

NULL встречаются только там, где пары нет, и обработаны ЕСТЬNULL

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

NULL попадают в суммы и сравнения, искажая итоги

Типичные ошибки и ограничения

Самая частая ошибка — несовпадение состава полей в объединяемых выборках. Платформа выдаст ошибку вида «Неверное количество полей» или «Несовместимые типы». Лечится выравниванием списков полей и приведением типов через ВЫРАЗИТЬ.

Вторая группа ошибок связана с временными таблицами как таковыми: обращение к таблице, которая ещё не создана в пакете (нарушен порядок запросов), использование разных менеджеров временных таблиц для создания и чтения, либо уничтожение таблицы оператором УНИЧТОЖИТЬ раньше времени. Помните: временные таблицы живут в рамках одного менеджера и одного выполнения пакета.

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

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

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

Альтернативы объединению в запросе

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

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

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

Сравнение подходов

ОБЪЕДИНИТЬ ВСЕ в запросе

Быстро и декларативно; требует одинакового состава полей и не подходит для сложной построчной логики

СОЕДИНЕНИЕ в запросе

Подходит для дополнения колонками по ключу; требует уникальности ключа и обработки NULL

Слияние ТаблицаЗначений в коде

Гибкая логика любой сложности; больше кода, медленнее на больших объёмах

Связь наборов данных в СКД

Удобно для отчётов с настройками; не подходит для произвольных программных выборок

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

Можно ли объединить более двух временных таблиц?

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

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

Напрямую через ОБЪЕДИНИТЬ — никак: состав полей обязан совпадать. Недостающие колонки добавьте константами (0, пустая строка, NULL). Если различий много и семантика колонок разная, вероятно, вам нужно соединение по ключу, а не объединение.

Почему после соединения временных таблиц удвоились суммы?

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

Что быстрее: ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ?

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

Как посмотреть содержимое временной таблицы при отладке?

В отладчике создайте вспомогательный запрос с тем же МенеджерВременныхТаблиц и текстом «ВЫБРАТЬ * ИЗ ИмяТаблицы», выполните его и проанализируйте результат. Альтернатива — консоль запросов, где временные таблицы пакета можно просматривать по отдельности без изменения кода.

Можно ли использовать временную таблицу из другого запроса?

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

Итог

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

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