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

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

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

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

Основная причина дублирования при работе с РегистрСведений заключается в нарушении логики соединения таблиц. Если мы соединяем одну и ту же таблицу саму с собой, используя лишь базовый ключ (например, Объект), система сопоставляет каждую запись первой выборки с каждой записью второй. Если у вас несколько «Исходящих звонков» и несколько пустых записей, база данных создает так называемое декартово произведение, что и приводит к появлению лишних дублей.

Для решения подобных задач необходимо не просто фильтровать данные в блоке ГДЕ, а правильно настраивать условия соединения ПО, ограничивая временной диапазон для каждой конкретной записи.

Решение через временные таблицы и объединение

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

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


// Формируем таблицу только с записями "Исходящий звонок"
ВЫБРАТЬ рег.* ПОМЕСТИТЬ втТаб 
ИЗ РегистрСведений.Активность КАК рег 
ГДЕ рег.Реквизит = "Исходящий звонок";

// Результирующая выборка
// 1. Сами строчки с "Исходящий звонок"
ВЫБРАТЬ втТаб.* ИЗ втТаб КАК втТаб
ОБЪЕДИНИТЬ ВСЕ
// 2. Дополнительные строчки с "" и интервалом 5 минут (300 секунд)
ВЫБРАТЬ рег.* 
ИЗ втТаб КАК втТаб
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.Активность КАК рег 
ПО втТаб.Объект = рег.Объект 
ГДЕ рег.Реквизит = "" 
И РАЗНОСТЬДАТ(втТаб.Период, рег.Период, СЕКУНДА) <= 300
И РАЗНОСТЬДАТ(втТаб.Период, рег.Период, СЕКУНДА) > 0;

В этом примере мы используем функцию РАЗНОСТЬДАТ, которая позволяет точно определить попадание записи в 5-минутный интервал от момента совершения звонка. Это исключает появление дублей, так как для каждой записи-источника мы находим строго определенный набор «потомков».

Когда лучше использовать Таблицу Значений

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

  1. Выгрузите все необходимые данные за период по объекту в ТаблицаЗначений одним простым запросом без сложных соединений.
  2. Отсортируйте полученную таблицу по полю Период.
  3. Проитерируйте (переберите) записи в цикле.
  4. При обнаружении записи с реквизитом «Исходящий звонок» зафиксируйте её время.
  5. Все последующие записи, у которых реквизит пустой и время попадает в интервал [Время звонка; Время звонка + 5 минут], добавляйте в результирующую выборку или помечайте для вывода.

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

Основные рекомендации по проектированию запросов

Чтобы избежать подобных проблем в будущем, запомните следующие правила:

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

← На главную