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

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

При работе с базами данных на платформе 1С:Предприятие разработчики регулярно сталкиваются с необходимостью построения сложных запросов к реквизитам составного типа. Типичным примером является реквизит ДокОснование или ГлавныйДокумент, который может ссылаться на несколько различных типов документов (например, Инцидент, Наряд, Релиз или Проблема). Задача отбора документов, у которых это поле не заполнено, часто вызывает трудности, так как стандартное сравнение «в лоб» не приносит ожидаемого результата. В этой статье мы подробно разберем, почему так происходит, и рассмотрим наиболее эффективные методы решения этой задачи в запросах и СКД.

Разберем теорию: почему возникают сложности с составными типами?

Для того чтобы понять, почему простые условия отбора не срабатывают, проанализируем структуру хранения составного типа данных в СУБД. В отличие от простого реквизита, составное поле на уровне базы данных под управлением SQL хранится в виде нескольких колонок. Платформа выделяет отдельные поля для хранения типа значения и непосредственно самого уникального идентификатора ссылки (GUID).

Когда пользователь оставляет поле составного типа незаполненным, в базе данных оно может быть представлено в одном из трех различных состояний:

  1. Значение НЕОПРЕДЕЛЕНО. Это дефолтное состояние реквизита составного типа, когда пользователь вообще не выбирал тип документа. На уровне базы данных в этом случае записывается специальный маркер отсутствия типа.
  2. Пустая ссылка конкретного типа (например, Документ.Инцидент.ПустаяСсылка). Такое состояние возникает, когда пользователь в интерфейсе сначала выбрал тип документа из списка составного типа, но сам документ в поле так и не выбрал (оставил строку выбора пустой).
  3. Значение NULL. Данное значение появляется в результате выполнения левых соединений (LEFT JOIN) в запросах, когда для конкретной строки левой таблицы не нашлось соответствия в правой таблице.

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

Метод 1. Проверка через системное свойство Ссылка ЕСТЬ NULL (Универсальный лайфхак)

Рассмотрим наиболее популярный, красивый и универсальный способ проверки составного поля на любое пустое значение в запросах 1С. Для этого мы обратимся к свойству Ссылка проверяемого реквизита через точку и применим оператор ЕСТЬ NULL.

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


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

Выясним причину, почему это условие работает безотказно:

Важное предупреждение по производительности: Обращение через точку к реквизиту составного типа (ДокОснование.Ссылка) заставляет платформу 1С генерировать SQL-запрос с левым соединением (LEFT JOIN) ко всем физическим таблицам документов, входящих в этот составной тип. Если составной тип содержит десятки различных видов документов, такой запрос может работать крайне медленно на больших объемах данных. Используйте этот метод аккуратно.

Метод 2. Решение непосредственно в СКД (Системе компоновки данных)

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

Выполним следующие шаги для настройки отбора в СКД:

  1. Откройте схему компоновки данных и перейдите на вкладку «Настройки».
  2. В окне настроек выберите вкладку «Отбор».
  3. Добавьте в список отборов поле ДокОснование (или ГлавныйДокумент).
  4. В колонке «Вид сравнения» выберите системный оператор «Не заполнено».

Платформа 1С при генерации итогового SQL-запроса самостоятельно проанализирует составной тип данных и построит максимально оптимальный и быстрый запрос к СУБД, который корректно обработает и НЕОПРЕДЕЛЕНО, и пустые ссылки всех типов, избегая при этом лишних непроизводительных соединений.

Метод 3. Оптимизация с использованием оператора ВЫРАЗИТЬ

В высоконагруженных системах, где важна каждая миллисекунда выполнения запроса, а составной тип реквизита включает в себя слишком много таблиц, использование обращения через точку нежелательно. В этом случае мы можем оптимизировать запрос, явно ограничив проверяемый тип с помощью оператора ВЫРАЗИТЬ.

Допустим, нам достоверно известно, что в контексте нашей задачи реквизит ДокОснование должен содержать только документ типа Инцидент, а все остальные варианты или пустоты мы считаем незаполненными. Разберем по шагам пример такого запроса:


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

При использовании конструкции ВЫРАЗИТЬ платформа не будет создавать соединения со всеми таблицами документов составного типа. Она выполнит соединение только с таблицей документа Инцидент, что существенно снизит нагрузку на СУБД и ускорит выполнение запроса.

Метод 4. Использование оператора ССЫЛКА (Альтернативный вариант из практики)

Иногда перед разработчиком стоит более специфическая задача: нужно отобрать документы, у которых в поле составного типа указан не конкретный документ (например, не Инцидент) или поле вовсе не заполнено. В обсуждении на форуме было предложено использовать оператор ССЫЛКА.

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


ВЫБРАТЬ
    НарядРасходы.Ссылка КАК Ссылка
ИЗ
    Документ.НарядРасходы КАК НарядРасходы
ГДЕ
    НЕ НарядРасходы.ДокОснование ССЫЛКА Документ.Инцидент

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

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

← На главную