Как вывести все элементы справочника и данные из регистра сведений, включая отсутствующие записи

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

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

Анализ проблемы: почему исчезают записи?

Рассмотрим ситуацию, описанную в теме. Автор пытается соединить справочник Спецификация с виртуальной таблицей СрезПоследних регистра сведений Выгрузка. Основная ошибка заключается в использовании регистра как «левой» (главной) таблицы и наложении жестких условий в секции ГДЕ. Когда мы пишем условие ГДЕ Регистр.Статус = &Статус, система отсекает все строки, где Статус равен NULL (то есть те, по которым записи в регистре отсутствуют). В итоге ЛЕВОЕ СОЕДИНЕНИЕ превращается по смыслу во ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Проанализируем исходный (проблемный) код:


ВЫБРАТЬ
    Спецификация.Ссылка,
    ВыгрузкаСрезПоследних.Статус
ИЗ
    РегистрСведений.Выгрузка.СрезПоследних КАК ВыгрузкаСрезПоследних
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Спецификация КАК Спецификация
        ПО ВыгрузкаСрезПоследних.ОбъектВыгрузки = Спецификация.Ссылка
ГДЕ
    ВыгрузкаСрезПоследних.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусВыгрузки.НеВыгружен)

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

Решение №1: Правильный выбор основной таблицы и структуры соединения

Чтобы в выборку попали все активные спецификации, основной таблицей в запросе должен выступать именно справочник. Мы «наслаиваем» данные регистра на справочник, а не наоборот. Посмотрим, как изменить структуру:

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

Разберем реализацию этого подхода:


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

Решение №2: Оптимизация через параметры виртуальной таблицы

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

Выясним, как это ускоряет работу: система передаст фильтр на уровень СУБД, и база данных вернет только те записи, которые соответствуют условию. Это критично, если в регистре миллионы записей.

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


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

В этом случае в результат попадут все спецификации. Те, у которых статус в регистре «НеВыгружен», будут иметь заполненное поле Статус. У всех остальных (включая тех, у кого другой статус или записи вообще нет) в поле Статус будет значение NULL.

Использование функции ЕСТЬNULL для оформления отчета

Чтобы пользователь не видел пустых полей в отчете, когда записи в регистре нет, используем функцию ЕСТЬNULL. Она позволяет заменить NULL на любое осмысленное значение или пустую ссылку типа. Проанализируем пример:

ЕСТЬNULL(ВыгрузкаСрезПоследних.Статус, ЗНАЧЕНИЕ(Перечисление.СтатусВыгрузки.ПустаяСсылка))

Это гарантирует, что при выводе в таблицу или обработке в коде у вас всегда будет объект ожидаемого типа, а не «пустота».

Важные рекомендации по производительности

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

Таким образом, для решения задачи мы должны четко следовать правилу: главная таблица — это справочник, а все фильтры на присоединяемую таблицу регистра должны либо учитывать возможность NULL, либо быть вынесены в параметры виртуальной таблицы.

← На главную