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