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

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

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

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

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

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

Разберем пример кода для создания «чистой» временной таблицы без повторов:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИсточникиЗагрязненияСостав.Наименование КАК ПроизводственнаяПлощадка
ПОМЕСТИТЬ ВТ_ПП
ИЗ
    Справочник.ОбъектыНВОСПоставленныеНаУчет.Состав КАК ИсточникиЗагрязненияСостав
ГДЕ
    ИсточникиЗагрязненияСостав.Ссылка = &ОбъектНВОС
    И ИсточникиЗагрязненияСостав.Наименование ССЫЛКА Справочник.ПроизводственныеПлощадки
;

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

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

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

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


ВЫБРАТЬ
    ИсточникиЗагрязнения.Ссылка,
    ИсточникиЗагрязнения.НомерИЗА,
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка
ИЗ
    Справочник.ИсточникиЗагрязнения КАК ИсточникиЗагрязнения
ГДЕ
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка В (ВЫБРАТЬ ВТ.ПроизводственнаяПлощадка ИЗ ВТ_ПП КАК ВТ)

Если в колонке Ссылка вы увидите разные значения для строк с одинаковыми номерами — значит, проблема не в запросе, а в «мусоре» внутри базы данных. В этом случае необходимо либо чистить справочник, либо использовать группировку.

Причина 3: Группировка и уникальность в итоговом запросе

Если специфика бизнес-логики такова, что дубли в справочнике возможны или допустимы, но в отчете их видеть не хочется, применим один из двух классических методов платформы 1С.

Метод А: Использование ключевого слова РАЗЛИЧНЫЕ

Этот метод подходит, если вам нужно просто скрыть идентичные строки. Система сравнит все выбранные поля и оставит только уникальные комбинации.


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИсточникиЗагрязнения.НомерИЗА КАК НомерИЗА,
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка КАК ПроизводственнаяПлощадка
ИЗ
    Справочник.ИсточникиЗагрязнения КАК ИсточникиЗагрязнения
ГДЕ
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка В (ВЫБРАТЬ ВТ.ПроизводственнаяПлощадка ИЗ ВТ_ПП КАК ВТ)

Метод Б: Использование СГРУППИРОВАТЬ ПО

Группировка более предпочтительна, если в будущем вы планируете добавлять в запрос числовые показатели (например, количество выбросов). Рассмотрим, как это выглядит:


ВЫБРАТЬ
    ИсточникиЗагрязнения.НомерИЗА КАК НомерИЗА,
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка КАК ПроизводственнаяПлощадка,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ИсточникиЗагрязнения.Ссылка) КАК КоличествоЗаписей
ИЗ
    Справочник.ИсточникиЗагрязнения КАК ИсточникиЗагрязнения
ГДЕ
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка В (ВЫБРАТЬ ВТ.ПроизводственнаяПлощадка ИЗ ВТ_ПП КАК ВТ)
СГРУППИРОВАТЬ ПО
    ИсточникиЗагрязнения.НомерИЗА,
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка

Оптимизация типизации данных

Посмотрим на условие ТИПЗНАЧЕНИЯ(ИсточникиЗагрязненияСостав.Наименование) = ТИП(Справочник.ПроизводственныеПлощадки). В 1С использование функции ТИПЗНАЧЕНИЯ в языке запросов считается «тяжелой» операцией, так как она заставляет СУБД выполнять дополнительные соединения с таблицами метаданных.

Правильнее и быстрее использовать оператор ССЫЛКА. Проанализируем правильный вариант:

ГДЕ ИсточникиЗагрязненияСостав.Наименование ССЫЛКА Справочник.ПроизводственныеПлощадки

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

Итоговый алгоритм исправления запроса

Рассмотрим финальный, оптимизированный вариант решения проблемы:

  1. Очищаем временную таблицу: Используем ВЫБРАТЬ РАЗЛИЧНЫЕ при помещении данных в ВТ_ПП.
  2. Добавляем индексацию: Если данных много, во временной таблице стоит добавить ИНДЕКСИРОВАТЬ ПО ПроизводственнаяПлощадка.
  3. Исправляем проверку типа: Заменяем ТИПЗНАЧЕНИЯ на оператор ССЫЛКА.
  4. Применяем итоговую фильтрацию: Используем РАЗЛИЧНЫЕ во втором запросе, чтобы исключить физические дубли ссылок из результата.

Пример чистого кода:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИсточникиЗагрязненияСостав.Наименование КАК ПроизводственнаяПлощадка
ПОМЕСТИТЬ ВТ_ПП
ИЗ
    Справочник.ОбъектыНВОСПоставленныеНаУчет.Состав КАК ИсточникиЗагрязненияСостав
ГДЕ
    ИсточникиЗагрязненияСостав.Ссылка = &ОбъектНВОС
    И ИсточникиЗагрязненияСостав.Наименование ССЫЛКА Справочник.ПроизводственныеПлощадки
ИНДЕКСИРОВАТЬ ПО
    ПроизводственнаяПлощадка
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ИсточникиЗагрязнения.НомерИЗА КАК НомерИЗА,
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка КАК ПроизводственнаяПлощадка
ИЗ
    Справочник.ИсточникиЗагрязнения КАК ИсточникиЗагрязнения
ГДЕ
    ИсточникиЗагрязнения.ПроизводственнаяПлощадка В
            (ВЫБРАТЬ
                ВТ_ПП.ПроизводственнаяПлощадка
            ИЗ
                ВТ_ПП)

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

← На главную