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

Программист 1С v8.3 (Управляемые формы) Управленческий учет Сфера услуг, туризм и социальный сектор
← На главную

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

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

Метод 1: Использование конструкции ОБЪЕДИНИТЬ ВСЕ с последующей группировкой

Этот метод является наиболее универсальным и часто используемым. Его суть заключается в том, что мы «склеиваем» результаты двух запросов один под другим, но в каждом из них создаем пустые колонки (с нулями) для данных из другого запроса.

Давайте разберем этот алгоритм по шагам:

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

Рассмотрим пример кода, реализующий эту логику:


ВЫБРАТЬ
    Т.Наименование КАК Наименование,
    СУММА(Т.Заказано) КАК Заказано,
    СУММА(Т.Продано) КАК Продано
ИЗ
    (ВЫБРАТЬ
        Туры.Наименование КАК Наименование,
        КОЛИЧЕСТВО(ЗаказТура.НомерСтроки) КАК Заказано,
        0 КАК Продано
    ИЗ
        Документ.ЗаказТура.ТабличнаяЧасть1 КАК ЗаказТура
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Туры КАК Туры ПО ЗаказТура.Тур = Туры.Ссылка
    СГРУППИРОВАТЬ ПО
        Туры.Наименование

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

    ВЫБРАТЬ
        Туры.Наименование,
        0,
        КОЛИЧЕСТВО(ЗаказТура.НомерСтроки)
    ИЗ
        Документ.ЗаказТура.ТабличнаяЧасть1 КАК ЗаказТура
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Туры КАК Туры ПО ЗаказТура.Тур = Туры.Ссылка
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПродажаТура КАК ПродажаТура ПО ЗаказТура.Ссылка = ПродажаТура.Тур.Ссылка
    СГРУППИРОВАТЬ ПО
        Туры.Наименование) КАК Т

СГРУППИРОВАТЬ ПО
    Т.Наименование

Важный нюанс: Обратите внимание, что во втором запросе мы обязательно должны указать 0 в колонке «Заказано», а в первом — 0 в колонке «Продано». Это позволяет функции СУММА в итоговом запросе корректно сложить данные, не смешивая их.

Метод 2: Работа через временные таблицы (рекомендуемый подход)

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

Рассмотрим пошагово, как реализовать задачу через МенеджерВременныхТаблиц:

  1. Создаем временную таблицу ВТ_Заказы, где группируем данные по турам.
  2. Создаем временную таблицу ВТ_Продажи, где также получаем итоги.
  3. В финальном запросе объединяем эти две таблицы.

Пример реализации с использованием временных таблиц:


// Шаг 1: Собираем заказы
ВЫБРАТЬ
    ЗаказТура.Тур КАК Тур,
    КОЛИЧЕСТВО(ЗаказТура.НомерСтроки) КАК Заказано
ПОМЕСТИТЬ ВТ_Заказы
ИЗ
    Документ.ЗаказТура.ТабличнаяЧасть1 КАК ЗаказТура
СГРУППИРОВАТЬ ПО
    ЗаказТура.Тур;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Собираем продажи
ВЫБРАТЬ
    ЗаказТура.Тур КАК Тур,
    КОЛИЧЕСТВО(ЗаказТура.НомерСтроки) КАК Продано
ПОМЕСТИТЬ ВТ_Продажи
ИЗ
    Документ.ЗаказТура.ТабличнаяЧасть1 КАК ЗаказТура
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПродажаТура КАК ПродажаТура ПО ЗаказТура.Ссылка = ПродажаТура.Тур.Ссылка
СГРУППИРОВАТЬ ПО
    ЗаказТура.Тур;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Объединяем и выводим наименования
ВЫБРАТЬ
    ЕСТЬNULL(ВТ_Заказы.Тур.Наименование, ВТ_Продажи.Тур.Наименование) КАК Наименование,
    ЕСТЬNULL(ВТ_Заказы.Заказано, 0) КАК Заказано,
    ЕСТЬNULL(ВТ_Продажи.Продано, 0) КАК Продано
ИЗ
    ВТ_Заказы КАК ВТ_Заказы
    ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Продажи КАК ВТ_Продажи ПО ВТ_Заказы.Тур = ВТ_Продажи.Тур

Почему стоит использовать ПОЛНОЕ СОЕДИНЕНИЕ и ЕСТЬNULL?

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

Функция ЕСТЬNULL(Значение, 0) — это обязательный инструмент при соединении таблиц. Если во второй таблице нет соответствующей записи, 1С вернет значение NULL. Математические операции с NULL (например, сложение в отчете) могут привести к непредсказуемым результатам или пустым ячейкам. Замена на 0 гарантирует корректность вычислений.

Важное замечание: Ссылка против Наименования

В исходном вопросе автор пытался объединять данные по полю Наименование. Рассмотрим, почему это считается плохой практикой:

Правило: Всегда выполняйте соединения и группировки по полю Ссылка (или Тур, если это реквизит типа Ссылка). К полю Наименование обращайтесь только в самом последнем запросе при выводе данных пользователю через точку (Тур.Наименование).

Решение через Систему компоновки данных (СКД)

Если ваша задача — создать отчет, то лучше всего воспользоваться встроенным механизмом СКД. Выясним, как это упрощает работу:

  1. Вы создаете два отдельных набора данных (два разных запроса).
  2. На закладке «Связи наборов данных» указываете, что они связаны по полю Тур.
  3. В настройках отчета просто выбираете нужные поля в детальные записи.

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

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

← На главную