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

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

Работа с Системой компоновки данных (СКД) часто преподносит сюрпризы, особенно когда отчет строится на основе нескольких наборов данных или использует внешние источники (например, таблицы MS SQL Server). Одной из самых коварных проблем является ситуация, когда стандартный отбор по значению "Не заполнено", "Пустая ссылка" или "NULL" просто игнорируется системой. При этом визуально в отчете мы видим пустые поля, а условное оформление для этих же полей отрабатывает корректно.

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

Причина 1: Особенности оптимизации запросов и уровни наложения отборов

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

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

Решение: Перенос отбора на уровень группировки.

  1. Перейдем в настройки отчета СКД.
  2. Выберем конкретную группировку (например, по ЗаказПоставщику), внутри которой должны фильтроваться данные.
  3. Настроим отбор именно для этой группировки, а не для всего отчета в целом.

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

Причина 2: Специфика внешних источников данных и типов SQL

При работе с внешними источниками через ODBC или прямой запрос к MS SQL часто возникает конфликт типов. В 1С ПустаяСсылка — это специфический объект, а в SQL пустое значение — это чаще всего NULL. Кроме того, строковые поля в SQL могут иметь тип char с фиксированной длиной, и тогда "пустая" строка на самом деле будет заполнена пробелами.

Выясним причину через использование вычисляемых полей. Если стандартный отбор "Не заполнено" не видит пустое значение, попробуем нормализовать данные. Создадим вычисляемое поле, которое будет возвращать строковый маркер:


Выбор 
    Когда ИмяПоля ЕСТЬ NULL Тогда "ПУСТО"
    Когда ИмяПоля = "" Тогда "ПУСТО"
    Иначе "ЗАПОЛНЕНО"
Конец

Теперь мы можем установить отбор по этому вычисляемому полю со значением Равно "ПУСТО". Этот метод работает безотказно, так как вычисляемые поля обрабатываются на финальном этапе компоновки результата.

Причина 3: Неправильное использование расширения языка запросов {ГДЕ ...}

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


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

Проанализируем поведение системы: если параметр &ЦФО имеет тип Строка и он не заполнен (пустая строка), СКД может решить, что условие задавать не нужно, и полностью исключит секцию ГДЕ из итогового запроса. В результате отчет выведет все данные, игнорируя попытку пользователя отобрать "пустые" значения.

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


ГДЕ 
    (&ОтбиратьПустые = ИСТИНА И Поступление.А_ЦФО = "")
    ИЛИ (Поступление.А_ЦФО = &ЦФО)

Методика отладки через консоль СКД

Если решение не очевидно, крайне важно посмотреть на исполняемый запрос. Исходный текст запроса в конфигураторе и то, что 1С реально отправляет в СУБД — это разные вещи.

Посмотрим на алгоритм отладки:

  1. Скачаем или воспользуемся встроенной "Консолью компоновки данных" (часть Инструментов разработчика).
  2. Загрузим в нее схему отчета и установим те же настройки отбора, которые не работают.
  3. Нажмем кнопку "Исполняемый запрос".
  4. Проанализируем секцию WHERE (ГДЕ). Если вы видите там условие 1=1 или отсутствие вашего поля, значит, СКД исключила отбор на этапе оптимизации.

Часто в консоли можно заметить, что СКД пытается сравнить Guid из SQL со строкой 1С, что приводит к пустому результату. В этом случае поможет явное приведение типов в запросе набора данных через ВЫРАЗИТЬ(Поле КАК Тип).

Почему условное оформление работает, а отбор нет?

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

Разберем еще один нюанс: использование функции ЕстьNull(). В запросах СКД, объединяющих несколько наборов, рекомендуется всегда оборачивать потенциально пустые поля из правых таблиц соединений:


ВЫБРАТЬ
    Заказ.Ссылка КАК Заказ,
    ЕстьNull(ВнешнийИсточник.ID, 0) КАК Идентификатор
ИЗ
    Заказы КАК Заказ

Это позволит избежать неопределенности при наложении стандартных фильтров компоновки данных.

← На главную