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

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

Приветствуем вас, коллеги! Сегодня мы детально разберем крайне неприятную и неочевидную техническую проблему, с которой часто сталкиваются разработчики при переходе на новые релизы платформы 1С:Предприятие (в частности, линейки 8.3.15, например 8.3.15.1830). Суть проблемы заключается в том, что в отчетах, построенных на Системе компоновки данных (СКД), внезапно перестают работать отборы по булевым реквизитам. Самое интересное и коварное здесь то, что ошибка возникает исключительно тогда, когда пользователь выбирает значение отбора "Нет" (то есть ЛОЖЬ). При выборе значения "Да" (ИСТИНА) все формируется без каких-либо замечаний.

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

Выясняем техническую причину сбоя

Для начала проанализируем, почему платформа ведет себя столь избирательно. Когда мы накладываем отбор со значением "Да" (ИСТИНА), СКД генерирует простой и понятный для СУБД SQL-запрос. Однако при выборе значения "Нет" (ЛОЖЬ) система компоновки пытается оптимизировать запрос и автоматически "пропихнуть" этот отбор непосредственно в параметры виртуальных таблиц (например, в параметры таблицы остатков или оборотов регистров накопления).

В релизах платформы 8.3.15 (и некоторых соседних ветках) механизм трансляции таких условий содержит внутренний дефект. При попытке преобразовать условие с отрицанием вида Номенклатура.НеПроизводится = ЛОЖЬ внутри параметров виртуальной таблицы транслятор запросов некорректно обрабатывает псевдонимы (алиасы) таблиц. В итоге СУБД получает искаженный SQL-код, возвращающий ошибку о неоднозначном поле (ambiguous field) или синтаксическую ошибку запроса.

Кроме того, существует и вторая скрытая причина. Если булево поле было добавлено в конфигурацию позже, чем появились сами элементы справочника, то в базе данных для старых элементов фактически записано значение NULL, а не ЛОЖЬ. Прямое сравнение с ЛОЖЬ отсекает эти записи, что делает результат отбора некорректным.

Ниже мы подробно разберем четыре практических варианта решения этой проблемы.

Способ 1. Использование фигурных скобок {} для явного наложения условий

Рассмотрим самый надежный и правильный метод решения проблемы с точки зрения стандартов разработки 1С. Нам необходимо запретить системе компоновки автоматически помещать отбор в параметры виртуальной таблицы и явно указать место наложения условия в секции ГДЕ основного запроса с помощью расширения языка запросов СКД.

Разберем по шагам, как изменить запрос в конструкторе схемы компоновки данных:

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

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


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

Использование конструкции {ГДЕ ...} гарантирует, что СКД применит пользовательский отбор корректно, избегая ошибочной автоматической оптимизации параметров виртуальной таблицы.

Способ 2. Замена стандартного отбора параметром данных СКД

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

Проанализируем этот вариант по шагам:

  1. В схеме компоновки данных перейдите на вкладку Параметры.
  2. Создайте новый параметр, например, &ИсключитьНеПроизводимые с типом значения Булево.
  3. Укажите для созданного параметра свойство Использование в значение Всегда. Поставьте флаг Запрещать пустые значения.
  4. В тексте запроса жестко пропишите условие с использованием этого параметра.

Посмотрим на пример реализации такого условия в запросе:


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

Такой подход полностью контролируется разработчиком на уровне написания SQL-запроса и исключает любые попытки платформы "самостоятельно" дописать ошибочные условия.

Способ 3. Предварительная фильтрация через временную таблицу

Этот способ незаменим, когда мы работаем со сложными запросами, содержащими левые соединения или объединения (ОБЪЕДИНИТЬ). Если виртуальная таблица сбоит при получении условий на булевы реквизиты связанных справочников, мы можем предварительно выбрать и отфильтровать нужные ссылки во временную таблицу.

Разберем пример реализации этого метода:


// Шаг 1: Выбираем ссылки с нужным отбором во временную таблицу
ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВтОтфильтрованнаяНоменклатура
ИЗ
    Справочник.Номенклатура КАК Номенклатура
{ГДЕ
    (Номенклатура.НеПроизводится = &НеПроизводится)}
;

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

Этот метод не только обходит баг платформы, но и положительно сказывается на производительности отчета при работе с большими базами данных, так как СУБД сначала ограничивает объем выборки по проиндексированному полю ссылки.

Способ 4. Корректная обработка значений NULL в базе данных

Если в вашем булевом реквизите могут проскакивать значения NULL (например, для старых записей, созданных до добавления реквизита), то СКД применит строгое сравнение, и эти записи просто пропадут из отчета при выборе значения "Нет".

Чтобы избежать этой проблемы, в самом запросе СКД обязательно оборачивайте булево поле в функцию ЕСТЬNULL:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    ЕСТЬNULL(Номенклатура.НеПроизводится, ЛОЖЬ) КАК НеПроизводитсяПоле
ИЗ
    Справочник.Номенклатура КАК Номенклатура

После этого на вкладке Настройки компоновки накладывайте пользовательский отбор уже на результирующее поле НеПроизводитсяПоле. В нем гарантированно будут только чистые значения ИСТИНА или ЛОЖЬ, что исключит неоднозначность при построении запроса.

Резюме

Мы подробно разобрали причины сбоя отборов по булевым реквизитам в СКД на платформе 8.3.15.1830 и изучили четыре надежных способа решения этой проблемы. Рекомендуем начать с явного указания условий через фигурные скобки {} или использования функции ЕСТЬNULL в запросах. Эти несложные приемы уберегут ваши отчеты от багов платформы и обеспечат стабильную работу программы при любых обновлениях!

← На главную