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

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

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

Основная сложность заключается в том, что поле Регистратор имеет составной тип данных. Прямая попытка наложить фильтр «через точку» (например, Регистратор.ВидОперации <> &Значение) приводит к тому, что из результирующей таблицы исчезают вообще все документы, у которых нет реквизита ВидОперации. В этой статье мы подробно разберем, почему это происходит и как правильно составить запрос, чтобы получить корректный результат.

Анализ проблемы: почему исчезают документы

Разберем ситуацию с точки зрения работы СУБД. Когда мы обращаемся к полю Регистратор.ВидОперации, платформа 1С на уровне SQL-запроса выполняет неявное левое соединение (LEFT JOIN) со всеми таблицами документов, которые могут выступать регистраторами для данного регистра. Если текущая запись регистра порождена документом РеализацияТоваровУслуг, у которого нет поля ВидОперации, результатом обращения будет NULL.

Согласно логике трехзначной логики SQL, любое сравнение с NULL (равенство, неравенство, больше или меньше) дает результат «Ложь» (Unknown). Таким образом, условие ГДЕ Регистратор.ВидОперации <> &Операция отсекает не только нужную нам операцию, но и все документы других типов, так как для них результат сравнения NULL <> &Операция не является истинным. Проанализируем способы решения этой задачи.

Способ 1. Использование конструкции ССЫЛКА и отрицания

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

Рассмотрим пример правильного условия в запросе:


ГДЕ НЕ (Регистратор ССЫЛКА Документ.ПриходныйОрдерНаТовары 
    И Регистратор.ВидОперации = &ИсключаемаяОперация)

В данном случае логика работает следующим образом:

  1. Если документ является Реализацией, условие в скобках дает «Ложь», инверсия НЕ превращает её в «Истину» — документ остается.
  2. Если документ является Приходным ордером с другой операцией, условие в скобках снова «Ложь», инверсия дает «Истину» — документ остается.
  3. И только если совпал и тип документа, и вид операции, условие в скобках становится «Истиной», а НЕ превращает её в «Ложь» — документ исключается.

Способ 2. Применение конструкции ВЫБОР КОГДА

Иногда удобнее использовать явное ветвление в блоке условий. Это особенно полезно, если логика отбора сложная и включает несколько видов документов. Посмотрим на реализацию этого подхода:


ГДЕ ВЫБОР 
    КОГДА Регистратор ССЫЛКА Документ.ПриходныйОрдерНаТовары 
        ТОГДА Регистратор.ВидОперации <> &ИсключаемаяОперация
    ИНАЧЕ ИСТИНА 
КОНЕЦ

Этот метод позволяет наглядно управлять поведением фильтра для разных типов регистраторов. Мы явно указываем, что для всех документов, кроме Приходного ордера, условие всегда возвращает ИСТИНА.

Способ 3. Оптимизация через ВЫРАЗИТЬ

При обращении к реквизитам через составное поле Регистратор, система может генерировать избыточные соединения с таблицами БД. Чтобы оптимизировать запрос и помочь планировщику SQL, крайне рекомендуется использовать функцию ВЫРАЗИТЬ. Это явно указывает платформе, к таблице какого именно документа нужно обратиться.

Проанализируем оптимизированный вариант запроса:


ГДЕ ВЫБОР 
    КОГДА Регистратор ССЫЛКА Документ.ПриходныйОрдерНаТовары 
        ТОГДА ВЫРАЗИТЬ(Регистратор КАК Документ.ПриходныйОрдерНаТовары).ВидОперации <> &ИсключаемаяОперация
    ИНАЧЕ ИСТИНА 
КОНЕЦ

Использование ВЫРАЗИТЬ исключает попытки поиска реквизита ВидОперации в других таблицах, что положительно сказывается на скорости выполнения запроса, особенно в крупных базах данных с большим количеством типов документов-регистраторов.

Особенности работы с виртуальными таблицами

Важно помнить, в какой именно таблице регистра мы пытаемся применить отбор. Выясним разницу между ними:

  1. Виртуальная таблица Остатки: Фильтрация по Регистратору здесь технически невозможна на уровне параметров виртуальной таблицы, так как остатки — это срез данных на момент времени, они не «помнят», каким документом созданы. Если нужно получить остатки за вычетом конкретных движений, придется вычитать обороты этих документов из общих остатков вручную в запросе.
  2. Виртуальная таблица Обороты: Здесь отбор по регистратору работает отлично. Рекомендуется накладывать его непосредственно в параметрах виртуальной таблицы (в поле «Условие»), так как это позволит системе отсечь ненужные записи на раннем этапе формирования выборки.
  3. Физическая таблица регистра: Если мы выбираем данные напрямую из основной таблицы (не виртуальной), все вышеперечисленные способы с ВЫРАЗИТЬ и ССЫЛКА обязательны к применению для обеспечения производительности.

Рекомендации по архитектуре

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

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

2. Использование СКД. При настройке отчетов в Системе компоновки данных (СКД), старайтесь выносить подобные условия в параметры виртуальных таблиц. СКД умеет интеллектуально преобразовывать условия, но использование конструкции ВЫБОР КОГДА ... ССЫЛКА ... внутри параметров все равно остается лучшей практикой.

3. Учет RLS. Помните, что обращение «через точку» к регистратору активирует механизмы ограничения прав доступа (RLS) для всех типов документов, входящих в составной тип. Если у пользователя нет прав на какой-то тип документа, запрос может завершиться ошибкой или работать крайне медленно. Явное приведение типа через ВЫРАЗИТЬ помогает минимизировать это влияние.

Таким образом, для решения задачи отбора по составному регистратору мы должны комбинировать проверку типа документа и корректную обработку значений NULL, не забывая о производительности запроса.

← На главную