Почему запрос с условием НЕ В возвращает пустой результат и как правильно искать отсутствующие записи в 1С?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача поиска элементов справочника, которые отсутствуют в каком-либо регистре сведений или другой таблице. На первый взгляд, самое очевидное решение — использовать конструкцию ГДЕ НЕ Ссылка В (...). Однако разработчики нередко сталкиваются с ситуацией, когда такой запрос возвращает пустой результат, хотя данные в базе точно есть. Проанализируем причины этой проблемы и разберем наиболее эффективные способы её решения.

Разбор типичной ошибки: избыточное разыменование полей

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


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

Первая и самая явная ошибка здесь — обращение ВариантыОбеспеченияТоварами.Номенклатура.Ссылка. Выясним причину, почему это плохо. Поле Номенклатура в регистре сведений уже является ссылочным типом. Оно хранит в себе уникальный идентификатор (GUID) объекта. Когда мы добавляем в конце .Ссылка, мы заставляем платформу выполнять лишнюю операцию разыменования.

Разыменование в языке запросов 1С на уровне СУБД (SQL) превращается в дополнительное соединение (JOIN) с таблицей справочника только для того, чтобы получить тот же самый GUID, который и так уже есть в таблице регистра. В некоторых случаях, особенно на определенных версиях платформы (например, 8.3.11), такая избыточная вложенность может приводить к некорректной работе оптимизатора запросов и возвращать пустой результат.

Рекомендация: всегда обращайтесь напрямую к полю-измерению, если оно имеет нужный вам ссылочный тип. Вместо Номенклатура.Ссылка пишите просто Номенклатура.

Коварство оператора НЕ В и значений NULL

Проанализируем более глубокую причину, почему условие НЕ В может «сломаться». Это стандартное поведение SQL, которое транслируется и в 1С: если подзапрос в условии В (...) или НЕ В (...) возвращает хотя бы одну строку со значением NULL, то весь результат основного запроса может стать пустым. Это происходит из-за особенностей трехзначной логики SQL (TRUE, FALSE, UNKNOWN).

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

Решение через ЛЕВОЕ СОЕДИНЕНИЕ

Посмотрим на более надежный и правильный с точки зрения производительности способ — использование Левого соединения. При таком подходе мы берем все записи из левой таблицы (Справочник) и пытаемся сопоставить их с записями из правой таблицы (Регистр). Там, где данных в регистре нет, мы получим значение NULL.

Разберем по шагам, как построить такой запрос:

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

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

Этот метод гораздо стабильнее, так как он корректно обрабатывает пустые значения и позволяет SQL-серверу более эффективно использовать индексы таблиц.

Использование временных таблиц для оптимизации

Если ваша база данных содержит десятки тысяч товаров, а регистр сведений — сотни тысяч записей, прямое соединение справочника с регистром может замедлить работу. Кроме того, в регистре может быть несколько записей для одной и той же номенклатуры (например, в разрезе складов), что приведет к дублированию строк в результате соединения до срабатывания фильтра NULL.

Рассмотрим вариант с использованием Временных Таблиц (ВТ). Это «золотой стандарт» разработки на 1С, который позволяет оптимизатору СУБД четко понимать структуру данных. Выполним задачу в два этапа:

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ВариантыОбеспечения.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТ_НоменклатураВРегистре
ИЗ
    РегистрСведений.ВариантыОбеспеченияТоварами КАК ВариантыОбеспечения
;

Шаг 2. Получение итогового списка:


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

Почему использование ВТ лучше?

Подведение итогов

Проанализировав ситуацию, мы выяснили, что ошибка «пустого результата» в запросах с условием НЕ В часто вызвана либо избыточным использованием .Ссылка, либо наличием значений NULL в данных.

Основные правила для написания качественных запросов:

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

← На главную