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

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

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

Выясняем причину появления дублей в Срезе последних

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

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

Решение 1: Использование агрегатных функций и группировки

Наиболее надежный способ «схлопнуть» дублирующиеся записи — это использование конструкции СГРУППИРОВАТЬ ПО совместно с агрегатной функцией МАКСИМУМ (или МИНИМУМ). Это позволяет нам явно указать системе, какое из нескольких значений мы хотим видеть в отчете, если их оказалось больше одного.

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


ВЫБРАТЬ
    МАКСИМУМ(ПараметрыСрезПоследних.Значение.Наименование) КАК ЗначениеНаименование,
    ПараметрыСрезПоследних.Объект.Владелец.Номер КАК НомерМОДЕЛЬ,
    ПараметрыСрезПоследних.Объект.Вид.Наименование КАК ОбъектВидНаименование
ПОМЕСТИТЬ АОГВ
ИЗ
    РегистрСведений.Параметры.СрезПоследних КАК ПараметрыСрезПоследних
ГДЕ
    ПараметрыСрезПоследних.Объект.Вид.Наименование = "МОДЕЛЬ"
    И ПараметрыСрезПоследних.Значение.Наименование <> "Помещение"
СГРУППИРОВАТЬ ПО
    ПараметрыСрезПоследних.Объект.Владелец.Номер,
    ПараметрыСрезПоследних.Объект.Вид.Наименование;

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

Решение 2: Оптимизация параметров виртуальной таблицы

Многие разработчики допускают ошибку, накладывая условия фильтрации в секции ГДЕ. Это заставляет сервер СУБД сначала выбрать последние записи для всех объектов регистра, а потом отсеивать их. Рассмотрим более эффективный подход — передачу условий напрямую в параметры виртуальной таблицы.

Проанализируем ситуацию: использование параметров позволяет платформе отсечь лишние записи еще на этапе формирования временной таблицы в памяти SQL-сервера. Это не только ускоряет отчет, но и снижает вероятность появления «мусорных» данных при соединениях.


// Правильное использование параметров виртуальной таблицы
ВЫБРАТЬ
    Параметры.Значение КАК Значение,
    Параметры.Объект КАК Объект
ИЗ
    РегистрСведений.ПараметрыОборудования.СрезПоследних(&Период, Вид = &ВидОборудования) КАК Параметры

Решение 3: Оптимизация структуры запроса при множественных соединениях

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

Рассмотрим прием «Один проход вместо пяти». Вместо создания пяти временных таблиц для каждого вида замка или оборудования, как это было показано в обсуждении на форуме, эффективнее выбрать все данные один раз и развернуть их в колонки с помощью функции ВЫБОР.


ВЫБРАТЬ
    Параметры.Объект.ЛицевойСчет КАК ЛицевойСчет,
    МАКСИМУМ(ВЫБОР
            КОГДА Параметры.Объект.Вид.Наименование = "Замок ГМТ – 20"
                ТОГДА Параметры.Значение
            ИНАЧЕ 0
        КОНЕЦ) КАК Замок20,
    МАКСИМУМ(ВЫБОР
            КОГДА Параметры.Объект.Вид.Наименование = "Замок ГМТ – 25"
                ТОГДА Параметры.Значение
            ИНАЧЕ 0
        КОНЕЦ) КАК Замок25
ПОМЕСТИТЬ ВТ_СводныеДанные
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов.СрезПоследних(&Период, ) КАК Параметры
СГРУППИРОВАТЬ ПО
    Параметры.Объект.ЛицевойСчет;

Преимущества этого метода:

  1. Значительно сокращается количество обращений к базе данных.
  2. Исключается риск «размножения» строк из-за некорректных соединений.
  3. Текст запроса становится более читаемым и легким для отладки.

Важные технические нюансы

При работе с большими запросами не забывайте про следующие правила:

Подводя итог, можно сказать, что «баг» с задвоением строк в 1С чаще всего является следствием неявных измерений регистра или особенностей работы СУБД с периодами. Использование МАКСИМУМ и правильная группировка — это стандарт де-факто для создания стабильных и отказоустойчивых отчетов.

← На главную