Почему в запросе 1С при использовании ОБЪЕДИНИТЬ ВСЕ строки не сворачиваются в одну и как это исправить?

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

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

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

Разберем причину: как работает ОБЪЕДИНИТЬ ВСЕ

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

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

Решение 1: Использование вложенного запроса

Это самый быстрый и распространенный способ. Мы помещаем конструкцию с ОБЪЕДИНИТЬ ВСЕ внутрь вложенного запроса, а во внешнем запросе выполняем агрегацию (суммирование) ресурсов.

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


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

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

В этом примере внешний запрос «видит» общий список номенклатуры из обоих регистров и благодаря инструкции СГРУППИРОВАТЬ ПО суммирует показатели в одну строку по каждому объекту СправочникСсылка.Номенклатура.

Решение 2: Использование временных таблиц

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

Рассмотрим по шагам, как это реализовать:

  1. Создаем первый запрос, который помещает объединенные данные во временную таблицу.
  2. Во втором запросе выбираем данные из этой временной таблицы и группируем их.

// Помещаем сырые данные во временную таблицу
ВЫБРАТЬ
    СтатьяДвиженияДенежныхСредств КАК Статья,
    Сумма КАК СуммаПлан,
    0 КАК СуммаФакт
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    РегистрНакопления.Бюджет
    
ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    СтатьяДДС,
    0,
    Сумма
ИЗ
    РегистрНакопления.ДенежныеСредства;

////////////////////////////////////////////////////////////////////////////////
// Группируем результат
ВЫБРАТЬ
    ВТ_Данные.Статья,
    СУММА(ВТ_Данные.СуммаПлан) КАК СуммаПлан,
    СУММА(ВТ_Данные.СуммаФакт) КАК СуммаФакт
ИЗ
    ВТ_Данные КАК ВТ_Данные
СГРУППИРОВАТЬ ПО
    ВТ_Данные.Статья

Тонкости сравнения типов (Субконто и Справочники)

Проанализируем ситуацию, описанную в сообщениях форума: когда данные берутся из управленческого регистра и регистра бухгалтерии. Если в одном случае измерение имеет тип СправочникСсылка.СтатьиДвиженияДенежныхСредств, а в другом — тип Характеристика.ВидыСубконтоХозрасчетные, группировка может не сработать.

Выясним причину: Для платформы 1С это разные типы данных. Даже если визуально в поле Субконто выбрана та же самая статья, система сравнивает их GUID-ы и типы. Чтобы группировка прошла успешно, типы нужно привести к общему знаменателю.

Используйте оператор ВЫРАЗИТЬ для приведения типа Субконто к конкретному справочнику:

ВЫРАЗИТЬ(СубконтоКт2 КАК Справочник.СтатьиДвиженияДенежныхСредств)

Проблема NULL при объединении

Посмотрим на пример из сообщения №14. В нем в качестве «пустых» значений используются NULL. Это допустимо, но требует осторожности. В языке запросов 1С операция СУММА(Поле) игнорирует NULL, однако если вы планируете выполнять арифметические операции с полями во внешнем запросе (например, СуммаПлан - СуммаФакт), наличие NULL приведет к тому, что результат всей операции станет NULL.

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

Практический пример: расчет среднего времени и сумм

Рассмотрим более сложный пример из сообщения №15, где объединяются данные об отработанном времени и начислениях сотрудников. Здесь используется сложная логика выбора коэффициентов в зависимости от месяца периода, а затем результат сворачивается по сотруднику:


ВЫБРАТЬ
    ВложенныйЗапрос.Сотрудник,
    СУММА(ВложенныйЗапрос.СреднеМесЧислоКалДней) КАК СреднеМесЧислоКалДней,
    СУММА(ВложенныйЗапрос.СуммаОборот) КАК СуммаОборот
ИЗ
    (ВЫБРАТЬ
        ОтработанноеВремя.Сотрудник КАК Сотрудник,
        // Сложная логика расчета коэффициента...
        ВЫБОР КОГДА ОтработанноеВремя.ОтработаноДней >= 17 ТОГДА 29.3 ИНАЧЕ 0 КОНЕЦ КАК СреднеМесЧислоКалДней,
        0 КАК СуммаОборот
    ИЗ
        РегистрНакопления.ОтработанноеВремяПоСотрудникам.Обороты(...) КАК ОтработанноеВремя
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        Начисления.Сотрудник,
        0,
        Начисления.СуммаОборот
    ИЗ
        РегистрНакопления.НачисленияУдержанияПоСотрудникам.Обороты(...) КАК Начисления) КАК ВложенныйЗапрос

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

Краткие итоги и рекомендации

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

  1. Оборачивайте объединение: Всегда используйте вложенный запрос или временную таблицу для финальной группировки.
  2. Соблюдайте типы: Убедитесь, что поля, по которым идет группировка, имеют одинаковый тип данных. Используйте ВЫРАЗИТЬ для полей с составным типом.
  3. Заполняйте ресурсы нулями: В тех частях объединения, где ресурс отсутствует, ставьте 0, а не оставляйте поле пустым.
  4. Имена колонок: Помните, что имена полей во вложенном запросе определяются по самому первому запросу в списке объединения. Именно к этим именам нужно обращаться во внешнем запросе.
  5. Использование СКД: Если вы работаете в системе компоновки данных, группировка часто происходит автоматически на уровне настроек отчета, но для корректного расчета ресурсов (например, когда нужно сложить данные из разных наборов) принципы вложенных запросов остаются актуальными.

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

← На главную