Почему запрос к виртуальной таблице ОстаткиИОбороты возвращает Регистратор = Неопределено?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Проанализируем ситуацию на примере следующего запроса:


ВЫБРАТЬ ПЕРВЫЕ 1
    ТоварыКОтгрузкеОстаткиИОбороты.Регистратор КАК Регистратор,
    ТоварыКОтгрузкеОстаткиИОбороты.КОтгрузкеПриход КАК КОтгрузкеПриход,
    ТоварыКОтгрузкеОстаткиИОбороты.КОтгрузкеРасход КАК КОтгрузкеРасход,
    ТоварыКОтгрузкеОстаткиИОбороты.КОтгрузкеКонечныйОстаток КАК КОтгрузкеКонечныйОстаток,
    ТоварыКОтгрузкеОстаткиИОбороты.Номенклатура КАК Номенклатура
ИЗ
    РегистрНакопления.ТоварыКОтгрузке.ОстаткиИОбороты(&д1, &д2, Регистратор, , Номенклатура = &ном) КАК ТоварыКОтгрузкеОстаткиИОбороты
ГДЕ
    ТоварыКОтгрузкеОстаткиИОбороты.КОтгрузкеКонечныйОстаток < 0
УПОРЯДОЧИТЬ ПО
    ТоварыКОтгрузкеОстаткиИОбороты.Регистратор.Дата

Если выполнить данный запрос, в первой строке в поле регистратор мы увидим Неопределено, а если убрать конструкцию ПЕРВЫЕ 1, то в последующих строках появятся нормальные ссылки на документы. Выясним причину такого поведения платформы.

Как формируются данные в таблице ОстаткиИОбороты

Разберем по шагам механику работы виртуальных таблиц регистров накопления. Виртуальная таблица ОстаткиИОбороты не существует физически в базе данных. В момент выполнения запроса она логически объединяет в себе данные из таблицы итогов (где хранятся остатки) и таблицы физических движений (где хранятся обороты).

Когда мы указываем в параметрах виртуальной таблицы периодичность Регистратор (или Авто, Запись), система генерирует результирующий набор данных, состоящий из строк двух видов:

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

Для служебных строк, которые показывают только остаток и не являются результатом конкретного движения в заданном периоде, физически не существует документа. База данных возвращает в эту колонку значение NULL. Платформа 1С при получении результатов запроса часто интерпретирует такие пустые ссылки как Неопределено или выводит пустую ячейку.

Влияние сортировки и выборки ПЕРВЫЕ 1

Посмотрим на пример из нашего кода. В запросе используется сортировка по возрастанию: УПОРЯДОЧИТЬ ПО ТоварыКОтгрузкеОстаткиИОбороты.Регистратор.Дата.

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

Именно из-за этого оператор ПЕРВЫЕ 1 постоянно захватывает служебную строку со значением Неопределено. Если вы проверите значения в этой строке, то убедитесь, что и КОтгрузкеПриход, и КОтгрузкеРасход будут равны нулю, так как физических оборотов в этой строке нет.

Как правильно решить эту задачу

Поведение системы абсолютно корректно и соответствует архитектуре 1С. Чтобы получить нужный результат и избавиться от пустых регистраторов, изменим подход. Рассмотрим три варианта решения проблемы в зависимости от исходной бизнес-задачи.

Вариант 1: Отсечь пустые значения в условии

Если нам нужны именно документы, совершившие движения, и их остатки после проведения, достаточно добавить проверку на заполненность поля регистратора в секцию ГДЕ:


ГДЕ
    ТоварыКОтгрузкеОстаткиИОбороты.КОтгрузкеКонечныйОстаток < 0
    И ТоварыКОтгрузкеОстаткиИОбороты.Регистратор ЕСТЬ НЕ NULL

Вариант 2: Использовать таблицу Обороты

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

Вариант 3: Настроить Метод дополнения

В параметрах виртуальной таблицы ОстаткиИОбороты существует специальный параметр — Метод дополнения. Если передать туда значение Движения, это заставит систему выводить данные только по тем строкам, где были реальные обороты документами, автоматически скрыв зависшие служебные строки с остатками без регистраторов.

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

← На главную