Как в запросе 1С проверить на пустое значение реквизит определяемого или составного типа?

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

Работа с определяемыми типами (Defined Types) в системе 1С:Предприятие 8.3 часто вызывает вопросы у разработчиков, особенно когда дело касается написания эффективных запросов. Основная сложность заключается в том, что определяемый тип по своей сути является составным типом данных. Это означает, что поле в базе данных может содержать не одно фиксированное значение, а значения самых разных типов: от ссылок на справочники и документы до примитивных типов, таких как строки или числа.

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

Поймем разницу: NULL, Неопределено и Пустая ссылка

Прежде чем переходить к коду запроса, нам необходимо проанализировать, как именно хранятся "пустые" значения в полях составного типа на уровне базы данных. В 1С существует три принципиально разных состояния "пустоты":

  1. НЕОПРЕДЕЛЕНО (Undefined): Это состояние поля, когда тип значения еще не был выбран. Например, если у вас есть реквизит составного типа и пользователь еще не взаимодействовал с ним. В базе данных это хранится как специальный маркер отсутствия типа.
  2. Пустая ссылка (Empty Reference): Это ситуация, когда тип значения уже определен (например, выбрано, что в поле будет храниться ссылка на справочник Контрагенты), но конкретный элемент справочника не выбран. Для каждого ссылочного типа в 1С существует своя уникальная пустая ссылка.
  3. NULL: Это специальное значение SQL, которое появляется в запросах чаще всего при левом соединении (ЛЕВОЕ СОЕДИНЕНИЕ), когда во второй таблице не найдена соответствующая запись.

Следовательно, простая проверка ГДЕ Поле ЕСТЬ NULL не найдет пустые ссылки справочников, а проверка ГДЕ Поле = НЕОПРЕДЕЛЕНО пропустит уже инициализированные, но пустые поля ссылочных типов.

Метод 1. Использование массива пустых значений (Рекомендуемый)

Наиболее универсальным и надежным способом является передача в запрос массива, содержащего все возможные варианты "пустоты" для данного определяемого типа. Мы соберем в этот массив значение Неопределено и пустые ссылки всех типов, входящих в состав определяемого типа.

Рассмотрим по шагам, как реализовать этот метод программно:


// 1. Получаем описание типов из метаданных определяемого типа
ОпределяемыйТипМетаданные = Метаданные.ОпределяемыеТипы.ИмяВашегоТипа;
ОписаниеТипов = ОпределяемыйТипМетаданные.Тип;

// 2. Формируем массив пустых значений
МассивПустыхЗначений = Новый Массив;
МассивПустыхЗначений.Добавить(Неопределено);

Для Каждого ТекущийТип Из ОписаниеТипов.Типы() Цикл
    // Проверяем, является ли тип ссылочным
    Если Справочники.ТипВсеСсылки().СодержитТип(ТекущийТип) 
        Или Документы.ТипВсеСсылки().СодержитТип(ТекущийТип) Тогда
        
        // Создаем пустую ссылку данного типа
        ПустаяСсылка = Новый(ТекущийТип);
        МассивПустыхЗначений.Добавить(ПустаяСсылка);
    КонецЕсли;
КонецЦикла;

// 3. Устанавливаем параметр в запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Т.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.РеализацияТоваровУслуг КАК Т
    |ГДЕ
    |   Т.РеквизитСоставногоТипа В (&МассивПустыхЗначений)";

Запрос.УстановитьПараметр("МассивПустыхЗначений", МассивПустыхЗначений);
Результат = Запрос.Выполнить();

Преимущество данного метода: Он работает максимально быстро, так как платформа 1С эффективно использует индексы при поиске по массиву значений (оператор В).

Метод 2. Трюк с проверкой ссылки на NULL

Существует альтернативный способ, который позволяет обойтись без формирования массива параметров. Мы можем попытаться обратиться к свойству Ссылка проверяемого поля. Если поле пустое (будь то Неопределено или пустая ссылка), то разыменование ссылки через точку вернет NULL.

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


ВЫБРАТЬ
    Т.Ссылка
ИЗ
    Документ.ПриходныйКассовыйОрдер КАК Т
ГДЕ
    Т.ОбъектРасчетов.Ссылка ЕСТЬ NULL

Важное предостережение: Несмотря на краткость, этот метод имеет серьезный недостаток. При выполнении такого запроса СУБД вынуждена выполнить LEFT JOIN ко всем таблицам, которые входят в этот составной тип. Если ваш определяемый тип включает в себя десятки документов и справочников, запрос станет крайне тяжелым и медленным. Используйте этот прием только в том случае, если типов в составе немного (2–3 типа).

Метод 3. Проверка через ТИПЗНАЧЕНИЯ

Если вам нужно найти только те записи, где тип вообще не был выбран (состояние Неопределено), можно использовать функцию языка запросов ТИПЗНАЧЕНИЯ. Выясним, как это выглядит на практике:


ВЫБРАТЬ
    Т.Ссылка
ИЗ
    Справочник.ДоговорыКонтрагентов КАК Т
ГДЕ
    ТИПЗНАЧЕНИЯ(Т.ДокументОснование) = ТИП(НЕОПРЕДЕЛЕНО)

Однако помните, что это условие не выберет записи с пустой ссылкой конкретного типа (например, пустую ссылку справочника Договоры). Поэтому данный метод редко применяется в чистом виде для поиска "пустоты".

Метод 4. Обработка примитивных типов

Если ваш определяемый тип, помимо ссылок, содержит примитивные типы (Число, Строка, Дата), то понятие "пустое значение" расширяется. Для системы 1С "пустыми" также будут считаться:

В таком случае при формировании массива из Метода 1 следует добавить и эти значения. Рассмотрим подробнее фрагмент кода для дополнения массива:


Если ОписаниеТипов.СодержитТип(Тип("Строка")) Тогда
    МассивПустыхЗначений.Добавить("");
КонецЕсли;

Если ОписаниеТипов.СодержитТип(Тип("Число")) Тогда
    МассивПустыхЗначений.Добавить(0);
КонецЕсли;

Если ОписаниеТипов.СодержитТип(Тип("Дата")) Тогда
    МассивПустыхЗначений.Добавить('00010101');
КонецЕсли;

Итоги и рекомендации

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

Подведем итог лучшей практики:

  1. Всегда учитывайте разницу между Неопределено и ПустаяСсылка.
  2. Избегайте конструкции Поле.Ссылка ЕСТЬ NULL для сложных определяемых типов с большим количеством таблиц, чтобы не перегружать SQL-сервер лишними соединениями.
  3. Используйте объект Метаданные для динамического получения типов, чтобы ваш код оставался работоспособным даже после изменения состава определяемого типа в конфигураторе.
  4. При работе с большими объемами данных отдавайте предпочтение оператору В (&Параметр), так как он лучше всего оптимизирован на уровне СУБД.

Соблюдение этих правил позволит вам писать надежные и производительные запросы для любых сложных типов данных в системе 1С.

← На главную