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

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

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

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

Причина возникновения дублей: механизм соединения таблиц

Проанализируем ситуацию на уровне базы данных. Когда мы пишем запрос и соединяем таблицу Документ.РеализацияТоваровУслуг с таблицей Документ.РеализацияТоваровУслуг.Товары по ссылке, СУБД выполняет операцию LEFT JOIN или INNER JOIN. Результатом такой операции является декартово произведение (в упрощенном виде): для каждой строки из левой таблицы подтягиваются все соответствующие строки из правой таблицы.

Даже если в самом отчете СКД мы выбираем для вывода только поля Ссылка, Номер и Дата, в итоговой выборке запроса все равно будет присутствовать столько записей, сколько строк в табличной части. СКД по умолчанию выводит «Детальные записи», то есть просто перебирает результат запроса строка за строкой. Рассмотрим, как это исправить.

Способ 1. Использование группировок вместо детальных записей

Это самый быстрый и часто используемый способ, который помог автору вопроса. Посмотрим на алгоритм настройки:

  1. Перейдем на вкладку Настройки в схеме компоновки данных.
  2. В структуре отчета найдем пункт Детальные записи.
  3. Нам необходимо либо удалить их, либо заменить на группировку. Нажмем правой кнопкой мыши на отчет и выберем «Новая группировка».
  4. В качестве поля группировки выберем Ссылка (или Номер, Дата — те поля, которые определяют уникальность документа).
  5. Внутри этой группировки на вкладке Выбранные поля укажем те данные, которые должен видеть пользователь.

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

Способ 2. Использование нескольких наборов данных

Рассмотрим более архитектурно правильный подход, который позволяет избежать раздувания выборки на этапе выполнения запроса. Вместо одного сложного запроса с СОЕДИНЕНИЕ, мы можем создать два независимых набора данных.

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

  1. Создадим НаборДанных1 (Запрос), в котором выберем только данные шапки документа.
  2. Создадим НаборДанных2 (Запрос), в котором выберем данные табличной части (Номенклатура, Количество и т.д.).
  3. Перейдем на вкладку Связи наборов данных.
  4. Свяжем их по полю Ссылка. Источником связи укажем первый набор, приемником — второй.

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

Способ 3. Условия в подзапросах (конструкция ГДЕ Ссылка В)

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


ВЫБРАТЬ
    Реализация.Ссылка КАК Ссылка,
    Реализация.Номер КАК Номер,
    Реализация.Дата КАК Дата,
    Реализация.Контрагент КАК Контрагент
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Ссылка В
        (ВЫБРАТЬ
            ТЧ.Ссылка
        ИЗ
            Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
        ГДЕ
            ТЧ.Номенклатура = &НоменклатураОтбор)

В СКД этот механизм можно сделать динамическим. Для этого в тексте запроса используются фигурные скобки {}, которые позволяют системе компоновки подставлять условия только тогда, когда пользователь активировал соответствующий отбор в интерфейсе. Это наиболее производительный метод для больших баз данных.

Способ 4. Роли полей и игнорирование дублей

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

Однако стоит помнить, что установка роли «Ключевое поле» сама по себе не удаляет дубли из детальных записей. Она лишь помогает СКД правильно строить иерархию и итоги. Поэтому использование ролей всегда должно идти в паре с правильной настройкой группировок, описанной в первом способе.

Способ 5. Ключевое слово РАЗЛИЧНЫЕ (DISTINCT)

Самый простой метод на уровне SQL — добавить ВЫБРАТЬ РАЗЛИЧНЫЕ в начало запроса. Рассмотрим ситуацию:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Реализация.Ссылка,
    Реализация.Номер,
    Реализация.Дата
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
    ПО Реализация.Ссылка = ТЧ.Ссылка

Осторожно: этот метод перестанет работать, если вы случайно добавите в список выбираемых полей хотя бы одно поле, уникальное для каждой строки табличной части (например, НомерСтроки или Количество). Поскольку СКД часто добавляет поля в запрос автоматически для обеспечения возможности отбора или сортировки, РАЗЛИЧНЫЕ может не дать ожидаемого результата.

Сравнительный анализ решений

Рассмотрим, какой метод выбрать в зависимости от условий задачи:

Таким образом, мы видим, что проблема дублей в СКД — это не ошибка системы, а следствие прямолинейного соединения таблиц. Переход от «Детальных записей» к осмысленным группировкам или разделение запросов на наборы данных позволяет создавать профессиональные и быстрые отчеты, удобные для конечного пользователя.

← На главную