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

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

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

Разбор причины: Декартово произведение и обращение к табличным частям

Проанализируем ситуацию, представленную в коде. Когда мы соединяем основную таблицу (например, документ СчетНаОплатуПокупателю) с его табличной частью или связанным справочником без четкого условия уникальности, СУБД формирует так называемое "декартово произведение". Если в документе есть табличная часть "Заявки на курс" и в двух строках указана одна и та же информация, обычное левое соединение (LEFT JOIN) вернет две строки вместо одной.

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

Решение 1: Оптимизация запроса с помощью группировки и временных таблиц

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

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

Посмотрим на пример кода, который заменяет проблемный запрос:


// Создаем запрос с использованием временных таблиц
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = 
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|	Счет.Ссылка КАК Ссылка,
|	Счет.Организация КАК Организация
|ПОМЕСТИТЬ ВТ_УникальныеДокументы
|ИЗ
|	Документ.СчетНаОплатуПокупателю КАК Счет
|ГДЕ
|	Счет.Ссылка = &Ссылка;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВТ.Организация КАК Организация,
|	Основания.Ссылка КАК ОснованиеПодписи,
|	Основания.Наименование КАК Наименование
|ИЗ
|	ВТ_УникальныеДокументы КАК ВТ
|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ОснованияПраваПодписи КАК Основания
|		ПО ВТ.Организация = Основания.Организация
|ГДЕ
|	Основания.Сотрудник = &Сотрудник
|СГРУППИРОВАТЬ ПО
|	ВТ.Организация,
|	Основания.Ссылка,
|	Основания.Наименование";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект);
Запрос.УстановитьПараметр("Сотрудник", ВыбранныйСотрудник);

Результат = Запрос.Выполнить();

Решение 2: Исправление антипаттерна "Запрос в цикле"

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

Рассмотрим, как это исправить. Мы должны сначала собрать все необходимые данные (параметры) в массив, передать этот массив в один-единственный запрос, получить результат и уже его выводить в печатную форму. Это гарантирует контроль над уникальностью записей на уровне одного результирующего набора данных.

Решение 3: Использование метода «Свернуть» для Таблицы Значений

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

Пример использования:


// Предположим, ТЗ_Данные содержит колонки "Сотрудник", "Должность", "Доверенность"
// Указываем колонки, по которым нужно сгруппировать данные
КолонкиГруппировки = "Сотрудник, Должность, Доверенность";
// Колонки суммирования оставляем пустыми, если нам нужно просто удалить дубли
КолонкиСуммирования = "";

ТЗ_Данные.Свернуть(КолонкиГруппировки, КолонкиСуммирования);

// Теперь ТЗ_Данные содержит только уникальные комбинации строк
Для Каждого СтрокаДанных Из ТЗ_Данные Цикл
    // Вывод в печатную форму
КонецЦикла;

Решение 4: Алгоритмическая проверка уникальности при выводе

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

Разберем этот метод по шагам:

  1. Создаем новый массив ВыведенныеСсылки = Новый Массив; перед началом цикла вывода.
  2. Внутри цикла проверяем, содержится ли текущий объект в массиве с помощью метода Найти().
  3. Если объект не найден — выводим область и добавляем ссылку в массив. Если найден — просто пропускаем итерацию.

ВыведенныеСсылки = Новый Массив;
Пока Выборка.Следующий() Цикл
    Если ВыведенныеСсылки.Найти(Выборка.Доверенность) = Неопределено Тогда
        // Заполняем параметры области
        ОбластьМакета.Параметры.Заполнить(Выборка);
        ТабДок.Вывести(ОбластьМакета);
        
        // Запоминаем, что мы уже вывели эту доверенность
        ВыведенныеСсылки.Добавить(Выборка.Доверенность);
    КонецЕсли;
КонецЦикла;

Решение 5: Устранение "невидимых" различий в данных

Часто ВЫБРАТЬ РАЗЛИЧНЫЕ не отрабатывает из-за того, что данные кажутся одинаковыми только визуально. Проанализируем ситуацию подробнее. Строки могут содержать невидимые пробелы или отличаться регистром, а даты — секундами. Для системы "Иванов " и "Иванов" — это разные значения.

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

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

← На главную