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

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

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

Почему появляются дубли при объединении?

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

Проанализируем ситуацию: даже при использовании предложения ИТОГИ ПО Номенклатура, визуально в консоли запросов или отчете мы увидим общую итоговую строку, но под ней все равно останутся "детальные" записи, которые выглядят как дубли. Чтобы избавиться от них и получить одну чистую строку на уровне детальных записей, нам нужно использовать дополнительные механизмы группировки.

Способ 1. Группировка через вложенный запрос

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

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

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

Пример реализации:


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

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

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

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

Важный момент: Обратите внимание на использование функции МАКСИМУМ() для полей, которые не являются измерениями, но которые вы хотите видеть в отчете (например, дата или ссылка на документ). Если для одной номенклатуры будет несколько заказов, группировка по ссылке все равно создаст разные строки. Если же задача — увидеть общие остатки в разрезе только номенклатуры, поля документов следует исключить из группировки.

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

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

Выполним следующие шаги:

  1. Выберем данные из заказов во временную таблицу ВТ_Заказы.
  2. Выберем остатки во временную таблицу ВТ_Остатки.
  3. Объединим их и сгруппируем в итоговом запросе.

// Помещаем заказы во временную таблицу
ВЫБРАТЬ
    Заказы.Номенклатура КАК Номенклатура,
    СУММА(Заказы.Количество) КАК Количество
ПОМЕСТИТЬ ВТ_Заказы
ИЗ
    Документ.ЗаказПоставщику.Товары КАК Заказы
ГДЕ
    Заказы.Ссылка.ДатаПоступления МЕЖДУ &НачПериода И &ВыбДата
СГРУППИРОВАТЬ ПО
    Заказы.Номенклатура;

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

СГРУППИРОВАТЬ ПО
    ИтоговыеДанные.Номенклатура

Способ 3. Левое или Полное соединение

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

Рассмотрим пример с полным соединением, чтобы не потерять товары, которые есть на остатках, но отсутствуют в заказах:


ВЫБРАТЬ
    ЕСТЬNULL(ВТ_Заказы.Номенклатура, ВТ_Остатки.Номенклатура) КАК Номенклатура,
    ЕСТЬNULL(ВТ_Заказы.Количество, 0) КАК КоличествоЗаказ,
    ЕСТЬNULL(ВТ_Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток
ИЗ
    ВТ_Заказы КАК ВТ_Заказы
        ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
        ПО ВТ_Заказы.Номенклатура = ВТ_Остатки.Номенклатура

Обратите внимание: При использовании соединений крайне важно использовать функцию ЕСТЬNULL для полей сопоставления. Если товара нет в заказах, поле ВТ_Заказы.Номенклатура будет содержать NULL, и без этой функции вы не увидите название товара в результате.

Особенности работы с итогами и иерархией

Если в вашем запросе используется конструкция ИТОГИ ... ПО Номенклатура ИЕРАРХИЯ, крайне важно, чтобы группировка данных была выполнена до расчета итогов. Если вы подадите на вход блоку ИТОГИ таблицу с дублями (где в одной строке заполнен заказ, а в другой — остаток), система может некорректно отобразить иерархические уровни или продублировать строки в группировках.

Правильный алгоритм всегда выглядит так: Подготовка данных (Соединение/Объединение) -> Группировка (Схлопывание дублей) -> Расчет Итогов.

Рекомендация по использованию СКД

Проанализируем ситуацию с точки зрения профессиональной разработки: если вы строите отчет, наиболее правильным методом будет использование Схемы компоновки данных (СКД). В СКД можно создать два отдельных набора данных (два разных запроса) и связать их на вкладке "Связи наборов данных" по полю Номенклатура. Система компоновки сама выполнит оптимальное соединение и корректно выведет итоги, не создавая лишних пустых строк, которые вам пришлось бы "выкостыливать" программно при выводе в табличный документ.

← На главную