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