Почему отбор СКД некорректно работает в пакете запросов с временными таблицами и как это исправить?

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

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

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


ВЫБРАТЬ
    5 КАК Оценка
ПОМЕСТИТЬ Оценки
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    4
;
ВЫБРАТЬ
    5 КАК Оценка,
    ИСТИНА КАК Хорошая
ПОМЕСТИТЬ ХорошиеОценки
;
ВЫБРАТЬ
    Оценки.Оценка КАК Оценка,
    ЕСТЬNULL(ХорошиеОценки.Хорошая, ЛОЖЬ) КАК Хорошая
ИЗ
    Оценки КАК Оценки
    ЛЕВОЕ СОЕДИНЕНИЕ ХорошиеОценки КАК ХорошиеОценки
    ПО Оценки.Оценка = ХорошиеОценки.Оценка

При установке пользовательского отбора Хорошая = Ложь ожидается получить только записи с оценкой 4. Однако система возвращает все строки (и 4, и 5). Выясним причину такого поведения платформы 1С:Предприятие и рассмотрим несколько вариантов правильного решения задачи.

В чем причина некорректного наложения отбора?

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

Поскольку поле Хорошая присутствует как во временной таблице ХорошиеОценки, так и в итоговом запросе выборки, компоновщик модифицирует пакет запросов следующим образом:


ВЫБРАТЬ
    5 КАК Оценка,
    ИСТИНА КАК Хорошая
ПОМЕСТИТЬ ХорошиеОценки
ГДЕ
    ИСТИНА = &П   // Сюда подставилось: ИСТИНА = ЛОЖЬ
;
ВЫБРАТЬ
    Оценки.Оценка КАК Оценка,
    ЕСТЬNULL(ХорошиеОценки.Хорошая, ЛОЖЬ) КАК Хорошая
ИЗ
    Оценки КАК Оценки
    ЛЕВОЕ СОЕДИНЕНИЕ ХорошиеОценки КАК ХорошиеОценки
    ПО Оценки.Оценка = ХорошиеОценки.Оценка
ГДЕ
    ЕСТЬNULL(ХорошиеОценки.Хорошая, ЛОЖЬ) = &П

В результате при отборе Хорошая = Ложь секция ГДЕ ИСТИНА = ЛОЖЬ делает временную таблицу ХорошиеОценки полностью пустой. При последующем левом соединении таблица Оценки ни с чем не соединяется, функция ЕСТЬNULL для всех строк возвращает ЛОЖЬ, и второе условие ГДЕ ЛОЖЬ = ЛОЖЬ становится истинным для абсолютно всех строк. Отчет выводит все оценки подряд.

Способ 1. Удаление лишнего поля из временной таблицы и проверка на NULL

Самое лаконичное и производительное решение — отказаться от создания искусственного логического поля во временной таблице. Достаточно проверить наличие записи через условие НЕ ... ЕСТЬ NULL в итоговой выборке.

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


ВЫБРАТЬ
    5 КАК Оценка
ПОМЕСТИТЬ Оценки
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    4
;
ВЫБРАТЬ
    5 КАК Оценка
ПОМЕСТИТЬ ХорошиеОценки
;
ВЫБРАТЬ
    Оценки.Оценка КАК Оценка,
    НЕ ХорошиеОценки.Оценка ЕСТЬ NULL КАК Хорошая
ИЗ
    Оценки КАК Оценки
    ЛЕВОЕ СОЕДИНЕНИЕ ХорошиеОценки КАК ХорошиеОценки
    ПО Оценки.Оценка = ХорошиеОценки.Оценка

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

Способ 2. Переименование поля во временной таблице

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

Разберем этот вариант на примере:


ВЫБРАТЬ
    5 КАК Оценка,
    ИСТИНА КАК ЭтоХорошаяОценкаВТ
ПОМЕСТИТЬ ХорошиеОценки
;
ВЫБРАТЬ
    Оценки.Оценка КАК Оценка,
    ЕСТЬNULL(ХорошиеОценки.ЭтоХорошаяОценкаВТ, ЛОЖЬ) КАК Хорошая
ИЗ
    Оценки КАК Оценки
    ЛЕВОЕ СОЕДИНЕНИЕ ХорошиеОценки КАК ХорошиеОценки
    ПО Оценки.Оценка = ХорошиеОценки.Оценка

Поскольку имя поля в отборе (Хорошая) больше не совпадает с полем временной таблицы (ЭтоХорошаяОценкаВТ), автозаполнение СКД не добавит фильтрацию в первый запрос пакета.

Способ 3. Отключение автозаполнения и явное описание условий СКД

Для полного контроля над поведением запроса снимем флаг Автозаполнение на вкладке Наборы данных и расставим инструкции расширения языка запросов СКД в фигурных скобках вручную.

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


ВЫБРАТЬ
    5 КАК Оценка,
    ИСТИНА КАК Хорошая
ПОМЕСТИТЬ ХорошиеОценки
;
ВЫБРАТЬ
    Оценки.Оценка КАК Оценка,
    ЕСТЬNULL(ХорошиеОценки.Хорошая, ЛОЖЬ) КАК Хорошая
{ВЫБРАТЬ
    Оценка,
    Хорошая}
ИЗ
    Оценки КАК Оценки
    ЛЕВОЕ СОЕДИНЕНИЕ ХорошиеОценки КАК ХорошиеОценки
    ПО Оценки.Оценка = ХорошиеОценки.Оценка
{ГДЕ
    (ЕСТЬNULL(ХорошиеОценки.Хорошая, ЛОЖЬ)) КАК Хорошая,
    Оценки.Оценка КАК Оценка}

Такой подход гарантирует, что пользовательский отбор по полю Хорошая встроится платформой исключительно в блок {ГДЕ ...} финального запроса.

Способ 4. Использование вычисляемых полей СКД

Еще один надежный способ — вынести вычисление флага на уровень схемы компоновки данных:

  1. В запросе оставим только ключевые поля связей без вычисления результирующего булева флага.
  2. Перейдем на вкладку Вычисляемые поля схемы компоновки.
  3. Добавим поле с именем Хорошая и выражением: Выбор Когда ОценкаХорошая Есть Не Null Тогда Истина Иначе Ложь Конец.
  4. В настройках отчета используем новое вычисляемое поле для отборов и вывода в отчет.

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

← На главную