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

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

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

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

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

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

Проанализируем ситуацию на примере кода. Сначала мы выбираем данные из первого регистра, подставляя 0 вместо поля второго регистра. Затем делаем наоборот.


ВЫБРАТЬ
    ВложенныйЗапрос.Склад КАК Склад,
    ВложенныйЗапрос.Номенклатура КАК Номенклатура,
    СУММА(ВложенныйЗапрос.ВНаличииОстаток) КАК ВНаличииОстаток,
    СУММА(ВложенныйЗапрос.КОформлениюПоступленийПоРаспоряжениюОстаток) КАК КОформлениюПоступленийПоРаспоряжениюОстаток
ИЗ
    (ВЫБРАТЬ
        ТоварыНаСкладахОстатки.Склад КАК Склад,
        ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
        ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ВНаличииОстаток,
        0 КАК КОформлениюПоступленийПоРаспоряжениюОстаток
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
    ГДЕ
        ТоварыНаСкладахОстатки.Склад = &Склад
        И ТоварыНаСкладахОстатки.Номенклатура = &Номенклатура

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

    ВЫБРАТЬ
        ТоварыКПоступлениюОстатки.Склад КАК Склад,
        ТоварыКПоступлениюОстатки.Номенклатура КАК Номенклатура,
        0 КАК ВНаличииОстаток,
        ТоварыКПоступлениюОстатки.КОформлениюПоступленийПоРаспоряжениюОстаток КАК КОформлениюПоступленийПоРаспоряжениюОстаток
    ИЗ
        РегистрНакопления.ТоварыКПоступлению.Остатки КАК ТоварыКПоступлениюОстатки
    ГДЕ
        ТоварыКПоступлениюОстатки.Склад = &Склад
        И ТоварыКПоступлениюОстатки.Номенклатура = &Номенклатура) КАК ВложенныйЗапрос

СГРУППИРОВАТЬ ПО
    ВложенныйЗапрос.Склад,
    ВложенныйЗапрос.Номенклатура

Важный нюанс: Если просто использовать ОБЪЕДИНИТЬ ВСЕ, система выдаст две разные строки для одной и той же номенклатуры. Чтобы «схлопнуть» эти строки в одну, мы обязательно используем внешний запрос с конструкцией СГРУППИРОВАТЬ ПО и агрегатной функцией СУММА для числовых полей.

Метод 2: Соединение таблиц (ЛЕВОЕ или ПОЛНОЕ СОЕДИНЕНИЕ)

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

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


ВЫБРАТЬ
    ЕСТЬNULL(ТаблицаОстатки.Склад, ТаблицаПоступления.Склад) КАК Склад,
    ЕСТЬNULL(ТаблицаОстатки.Номенклатура, ТаблицаПоступления.Номенклатура) КАК Номенклатура,
    ЕСТЬNULL(ТаблицаОстатки.ВНаличииОстаток, 0) КАК ВНаличииОстаток,
    ЕСТЬNULL(ТаблицаПоступления.КОформлениюПоступленийПоРаспоряжениюОстаток, 0) КАК КОформлениюПоступленийПоРаспоряжениюОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки( , Склад = &Склад И Номенклатура = &Номенклатура) КАК ТаблицаОстатки
        ПОЛНОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыКПоступлению.Остатки( , Склад = &Склад И Номенклатура = &Номенклатура) КАК ТаблицаПоступления
        ПО ТаблицаОстатки.Склад = ТаблицаПоступления.Склад
            И ТаблицаОстатки.Номенклатура = ТаблицаПоступления.Номенклатура

В этом примере крайне важно использовать функцию ЕСТЬNULL. При полном соединении, если данных в одной из таблиц нет, система подставит значение NULL. Функция ЕСТЬNULL(Поле, 0) заменяет пустоту на ноль, что позволяет корректно отображать числовые данные в отчете.

Оптимизация работы с виртуальными таблицами

Проанализируем производительность. В исходных запросах часто используется конструкция ГДЕ после выбора из виртуальной таблицы. В 1С это считается неоптимальным. Посмотрим на правильный вариант использования параметров виртуальных таблиц:

Вместо того чтобы писать:

ИЗ РегистрНакопления.ИмяРегистра.Остатки КАК Остатки ГДЕ Склад = &Склад

Следует писать:

ИЗ РегистрНакопления.ИмяРегистра.Остатки(&Период, Склад = &Склад) КАК Остатки

Это заставляет СУБД фильтровать данные еще в момент получения итогов, а не после того, как все остатки будут подняты в память. Для больших баз данных это критически важно.

Метод 3: Использование временных таблиц

Если запрос становится сложным, рекомендуется использовать Менеджер временных таблиц. Рассмотрим этот алгоритм:

  1. Помещаем остатки из первого регистра во временную таблицу ВТ_ОстаткиНаСкладах.
  2. Помещаем остатки из второго регистра во временную таблицу ВТ_ТоварыКПоступлению.
  3. В третьем запросе пакета соединяем эти таблицы.

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

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

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

В СКД можно создать два набора данных (запроса). На закладке «Связи наборов данных» мы указываем, что эти запросы связаны по полям Склад и Номенклатура. Система компоновки данных сама выполнит соединение, корректно обработает отсутствие записей в одном из регистров и выведет результат в нужные колонки. При этом вам не придется писать сложный код с группировками и ЕСТЬNULL — СКД сделает это автоматически.

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

← На главную