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