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

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

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

Рассмотрим ситуацию: в системе создан дополнительный реквизит «Признак доставка» с типом Булево. Если пользователь устанавливает галочку, запись в табличной части документа появляется. Если галочка не установлена — запись может либо содержать значение «Ложь», либо отсутствовать вовсе. В этой статье мы разберем, как правильно составить запрос, чтобы найти такие «пустые» документы.

Почему обычный фильтр в запросе не работает

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


ВЫБРАТЬ
    СоглашенияСПоставщиками.Ссылка
ИЗ
    Справочник.СоглашенияСПоставщиками КАК СоглашенияСПоставщиками
ГДЕ
    СоглашенияСПоставщиками.ДополнительныеРеквизиты.Свойство <> &НужноеСвойство

Выясним причину, почему этот подход неверен. Табличная часть ДополнительныеРеквизиты — это коллекция. Если у документа есть три других реквизита, но нет искомого, условие <> сработает для каждой из этих трех строк, и документ попадет в выборку. Если же у документа есть искомый реквизит (например, со значением «Истина») и еще пара других, то из-за наличия других строк документ все равно может попасть в результат. Более того, если у документа вообще нет записей в доп. реквизитах, такой запрос может их проигнорировать.

Решение №1: Использование ЛЕВОГО СОЕДИНЕНИЯ (Рекомендуемый способ)

Наиболее эффективный и правильный с точки зрения производительности метод — это использование ЛЕВОГО СОЕДИНЕНИЯ основной таблицы документа с его же табличной частью, но с фильтром по конкретному свойству в условии соединения.

Разберем этот метод по шагам:

  1. Выбираем основную таблицу документов (например, СоглашенияСПоставщиками).
  2. Присоединяем к ней таблицу ДополнительныеРеквизиты.
  3. Важно: Условие по конкретному свойству переносим в секцию ПО (связи), а не в ГДЕ.
  4. В секции ГДЕ оставляем только проверку на NULL для присоединенной таблицы.

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


ВЫБРАТЬ
    ДокументОбъект.Ссылка КАК Ссылка,
    ДокументОбъект.Наименование КАК Наименование
ИЗ
    Справочник.СоглашенияСПоставщиками КАК ДокументОбъект
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СоглашенияСПоставщиками.ДополнительныеРеквизиты КАК ТаблицаРеквизитов
        ПО ДокументОбъект.Ссылка = ТаблицаРеквизитов.Ссылка
            И (ТаблицаРеквизитов.Свойство = &ЦелевоеСвойство)
ГДЕ
    ТаблицаРеквизитов.Ссылка ЕСТЬ NULL

Как это работает: Система пытается сопоставить каждому документу строку из доп. реквизитов, где свойство совпадает с заданным. Если такой строки нет, то для всех полей таблицы ТаблицаРеквизитов вернется значение NULL. Условие ЕСТЬ NULL отфильтрует именно те документы, для которых запись не была найдена.

Решение №2: Использование конструкции «ГДЕ НЕ Ссылка В (...)»

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


ВЫБРАТЬ
    Документы.Ссылка
ИЗ
    Справочник.СоглашенияСПоставщиками КАК Документы
ГДЕ
    НЕ Документы.Ссылка В 
        (ВЫБРАТЬ
            ТЧ.Ссылка
        ИЗ
            Справочник.СоглашенияСПоставщиками.ДополнительныеРеквизиты КАК ТЧ
        ГДЕ
            ТЧ.Свойство = &ЦелевоеСвойство)

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

Особенности работы с типом «Булево» и БСП

В типовых конфигурациях 1С (ERP, УТ 11, КА) механизм дополнительных реквизитов оптимизирован. Для экономии места значение Ложь (снятая галочка) часто просто не записывается в базу данных. Это означает следующее:

Поэтому, если ваша задача — найти все документы, где «галочка не стоит», вам нужно искать именно отсутствие записи (как показано в решениях выше), а не строку со значением Ложь.

Как правильно передавать свойство в запрос

Никогда не сравнивайте свойство со строкой (синонимом), как это пытался сделать автор в начале обсуждения (Свойство <> "Признак доставка..."). Свойство — это ссылка на элемент Плана видов характеристик ДополнительныеРеквизитыИСведения.

Правильнее всего найти ссылку на свойство программно и передать её в параметр запроса:


// Поиск свойства по имени (внутреннему идентификатору для разработчика)
СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Признак доставка (Справочник ""Соглашения с поставщиками"")");

Запрос = Новый Запрос;
Запрос.Текст = "... (текст запроса выше) ...";
Запрос.УстановитьПараметр("ЦелевоеСвойство", СвойствоСсылка);

Совет: Если вы используете БСП, лучше искать свойство по его уникальному имени, заданному при создании, используя методы программного интерфейса БСП, чтобы избежать проблем при изменении заголовка пользователем.

Различие между Реквизитами и Сведениями

Важно не путать эти два механизма:

  1. Дополнительные реквизиты — хранятся в табличной части самого объекта. Наш пример выше относился именно к ним.
  2. Дополнительные сведения — хранятся в независимом регистре сведений ДополнительныеСведения.

Если вам нужно найти объекты без определенных сведений, принцип запроса останется тем же (левое соединение), но обращаться нужно будет к регистру:


ВЫБРАТЬ
    Объекты.Ссылка
ИЗ
    Справочник.СоглашенияСПоставщиками КАК Объекты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДополнительныеСведения КАК Сведения
        ПО Объекты.Ссылка = Сведения.Объект
            И (Сведения.Свойство = &ЦелевоеСвойство)
ГДЕ
    Сведения.Свойство ЕСТЬ NULL

Оптимизация производительности

При работе с огромными массивами данных (сотни тысяч документов) рекомендуется:

Таким образом, мы рассмотрели основные способы решения задачи. Выбор между LEFT JOIN и NOT IN зависит от ваших предпочтений в читаемости кода и объема данных в конкретной базе.

← На главную