Как правильно сгруппировать данные в отчете 1С и избавиться от дублей

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

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

Почему возникают дубли в запросах

Разберем типичную ошибку. Если в тексте запроса в секции ИЗ просто перечислить несколько таблиц через запятую, не указав условия связи, система выполнит так называемое «Декартово произведение» (Cross Join). Это означает, что каждая строка из первой таблицы будет объединена с каждой строкой из второй и третьей таблиц. Если у вас 10 договоров и 5 дополнительных соглашений, на выходе вы получите 50 строк.

Рассмотрим пример некорректного запроса:


ВЫБРАТЬ
    ДоговорНаПроектирование.Ссылка,
    ДополнительноеСоглашение.Ссылка
ИЗ
    Документ.ДоговорНаПроектирование КАК ДоговорНаПроектирование,
    Документ.ДополнительноеСоглашение КАК ДополнительноеСоглашение

В таком виде запрос работать не будет — он выдаст все возможные комбинации документов. Чтобы данные «схлопнулись», нам необходимо указать системе, по какому полю эти таблицы связаны. В строительстве таким полем обычно выступает ОбъектСтроительства.

Настройка правильных соединений (JOIN)

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

  1. Внутреннее соединение (INNER JOIN): Выводит только те записи, которые есть в обеих таблицах. Если у договора нет ни одного доп. соглашения, такой договор вообще не попадет в отчет.
  2. Левое соединение (LEFT JOIN): Выводит все записи из первой (левой) таблицы и добавляет к ним данные из правой, если они есть. Если данных в правой таблице нет, поля будут заполнены значением NULL. Это наиболее подходящий вариант для отчетов по объектам строительства, так как по объекту всегда есть основной договор, а дополнительные соглашения или договоры субподряда могут отсутствовать.

Проанализируем исправленный вариант запроса с использованием левого соединения:


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

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

Как убрать дубли, если связей несколько

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

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

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

Пример группировки:


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

Фильтрация по периоду и установка параметров

Часто отчет не выводит данные или выводит лишние из-за неправильной работы с датами. В 1С тип Дата включает время. Если вы передадите в параметр дату «01.08.2023», система воспримет это как начало дня — «01.08.2023 00:00:00». Документы, созданные в течение этого дня, не попадут в выборку МЕЖДУ.

Для корректной фильтрации разберем использование функции КОНЕЦПЕРИОДА:


ГДЕ
    Договор.Дата МЕЖДУ &ДатаНачала И КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ)

Функция КОНЕЦПЕРИОДА установит время на 23:59:59, что позволит захватить все документы за последний день периода.

При программной установке параметров в модуле формы, убедитесь, что вы обращаетесь к реквизитам правильно. Если параметры определены на форме отчета, используйте следующий подход:


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

Рекомендации по отладке сложных отчетов

Если вы запутались в соединениях и не понимаете, какая таблица «множит» строки, воспользуйтесь методом исключения:

И помните: для разработки сложных отчетов в современной 1С лучше всего использовать СКД (Систему компоновки данных). Она берет на себя большинство задач по группировке, расчету итогов и корректному выводу данных без дублей, предоставляя пользователю гибкие настройки внешнего вида отчета без переписывания кода запроса.

← На главную