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

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При работе с запросами в системе 1С:Предприятие программисты часто сталкиваются с необходимостью отфильтровать данные по пустому значению. Если поле имеет простой ссылочный тип (например, только Справочник.Номенклатура), задача решается легко. Однако, когда поле является составным (может содержать ссылки на разные типы документов или справочников), возникают сложности. Обычная попытка обратиться к ПустаяСсылка без указания конкретного типа приводит к ошибке «Неверные параметры», так как система не понимает, пустую ссылку какого именно объекта нужно проверить.

В этой статье мы подробно разберем, как правильно составить условие отбора, если поле (например, ЗаказРезерв) может быть не заполнено, и как оптимизировать такие запросы для повышения производительности системы.

Понимание природы «пустоты» в составных типах

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

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

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

Способ 1. Явное перечисление всех вариантов (Классический подход)

Если мы заранее знаем, какие типы документов могут входить в составное поле, мы можем перечислить их пустые ссылки вместе с проверкой на НЕОПРЕДЕЛЕНО. Это самый прозрачный, хотя и громоздкий метод.

Пример кода в тексте запроса:


ГДЕ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = &Заказ
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = НЕОПРЕДЕЛЕНО
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка)
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = ЗНАЧЕНИЕ(Документ.ЗаказНаПроизводство.ПустаяСсылка)
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.Ссылка.Склад = &Склад

Важный момент: Обратите внимание, что нельзя писать ЗНАЧЕНИЕ(Документы.ПустаяСсылка). Нужно обязательно указывать конкретный метаданный объект: Документ.ИмяДокумента.ПустаяСсылка.

Способ 2. Использование конструкции Ссылка ЕСТЬ NULL (Универсальный метод)

Существует изящный прием, позволяющий проверить поле на «пустоту» (будь то НЕОПРЕДЕЛЕНО или любая ПустаяСсылка) без перечисления всех типов. Мы можем попытаться обратиться через точку к любому стандартному реквизиту объекта, например, к самой ссылке.

Проанализируем ситуацию: если поле ЗаказРезерв содержит реальную ссылку, то обращение ЗаказРезерв.Ссылка вернет значение. Если же там НЕОПРЕДЕЛЕНО или пустая ссылка любого типа, то попытка обращения к реквизиту в языке запросов 1С вернет NULL.

Пример реализации:


ГДЕ (ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = &Заказ 
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв.Ссылка ЕСТЬ NULL)
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.Ссылка.Склад = &Склад

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

Способ 3. Проверка через ТИПЗНАЧЕНИЯ

Если нам нужно проверить именно отсутствие выбора (состояние НЕОПРЕДЕЛЕНО), мы можем использовать функцию ТИПЗНАЧЕНИЯ. Это работает быстро и эффективно.


ГДЕ ТИПЗНАЧЕНИЯ(ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв) = ТИП(НЕОПРЕДЕЛЕНО)
    ИЛИ ОтчетПроизводстваЗаСменуПродукция.ЗаказРезерв = &Заказ

Однако помните, что это условие не поймает пустые ссылки конкретных типов. Оно найдет только те записи, где тип вообще не определен.

Оптимизация: Замена ИЛИ на ОБЪЕДИНИТЬ ВСЕ

В процессе обсуждения было отмечено, что использование оператора ИЛИ в секции ГДЕ может существенно замедлить запрос. Это происходит потому, что СУБД (например, MS SQL Server) не всегда может эффективно построить план запроса с использованием индексов, когда условия комбинируются через ИЛИ.

Разберем, как сделать запрос более производительным. Вместо одного запроса с множеством условий ИЛИ, мы разделим его на несколько частей и объединим результаты.

Схема оптимизированного запроса:


ВЫБРАТЬ Ссылка, Продукция ИЗ Документ.ОтчетПроизводстваЗаСмену.Продукция
ГДЕ ЗаказРезерв = &Заказ

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ Ссылка, Продукция ИЗ Документ.ОтчетПроизводстваЗаСмену.Продукция
ГДЕ Ссылка.Склад = &Склад

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ Ссылка, Продукция ИЗ Документ.ОтчетПроизводстваЗаСмену.Продукция
ГДЕ ЗаказРезерв.Ссылка ЕСТЬ NULL

Почему это лучше? В таком виде для каждой части запроса система сможет использовать наиболее подходящий индекс (индекс по полю ЗаказРезерв, индекс по полю Склад и т.д.). В итоге общее время выполнения может быть в разы меньше, чем у одного сложного запроса.

Типичные ошибки при работе с составными типами

  1. Ошибка в Значение(): Попытка использовать ЗНАЧЕНИЕ(Справочник.ПустаяСсылка) или ЗНАЧЕНИЕ(Документы.ПустаяСсылка). Внутри функции ЗНАЧЕНИЕ всегда должен быть указан конкретный тип из метаданных.
  2. Проверка только на NULL: Новички часто пишут ГДЕ Поле ЕСТЬ NULL, забывая, что в базе данных 1С физически незаполненные поля обычно хранятся как НЕОПРЕДЕЛЕНО или пустые ссылки, а NULL — это виртуальное понятие только для соединений.
  3. Игнорирование параметров: Если вы передаете в запрос параметр &Заказ, который является пустой ссылкой конкретного документа, 1С отработает это как сравнение по конкретному типу, и записи с НЕОПРЕДЕЛЕНО или пустыми ссылками других типов в выборку не попадут.

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

← На главную