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

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

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

Разберем механизм работы виртуальной таблицы

Для начала проанализируем, как платформа 1С формирует данные в виртуальной таблице ОстаткиИОбороты. В отличие от реальных таблиц базы данных, виртуальная таблица не хранит информацию в готовом виде — она вычисляет её в момент обращения. Когда мы указываем периодичность Регистратор, система выполняет сложное соединение данных из таблиц итогов и таблиц движений.

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

Рассмотрим пример. Если мы сформируем запрос за период с 01.08.2024 по 05.08.2024 (подобная логика часто встречается в тестовых заданиях на собеседованиях), и на 01.08.2024 на складе уже лежало 10 единиц товара, система обязана выдать нам строку с начальным остатком. Но так как приход этого товара был, например, в июле, июльский документ не попадает в выборку как регистратор, и мы видим пустую ячейку.

Проанализируем влияние параметров виртуальной таблицы

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


РегистрНакопления.ИмяРегистра.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор, МетодДополнения, &Отбор)

Выясним роль параметра МетодДополнения (полезно также изучить добавление данных в существующую временную таблицу). Он может принимать два значения:

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

Разберем ситуацию с пустыми ссылками и NULL

Важно различать, что именно возвращает запрос в поле Регистратор. Проанализируем два варианта:

1. Значение NULL: Чаще всего в виртуальных таблицах остатков и оборотов поле Регистратор принимает значение NULL для строк, представляющих собой "чистые" остатки без оборотов в данном интервале.

2. Пустая ссылка: Если в самом регистре каким-то образом оказалась запись с незаполненным регистратором (что является ошибкой структуры данных), запрос вернет пустую ссылку соответствующего типа документа. Но в случае с ОстаткиИОбороты мы почти всегда имеем дело именно с техническим NULL.

Как убрать пустые регистраторы из результата запроса

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

Способ 1: Использование условия ГДЕ

Проанализируем пример кода, в котором мы отсекаем пустые значения регистратора прямо в тексте запроса:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   Резервы.Регистратор КАК Регистратор,
    |   Резервы.Номенклатура КАК Номенклатура,
    |   Резервы.КоличествоПриход КАК Приход,
    |   Резервы.КоличествоРасход КАК Расход
    |ИЗ
    |   РегистрНакопления.клмРезервированиеТоваров.ОстаткиИОбороты(&ДатаНач, &ДатаКон, Регистратор, , ) КАК Резервы
    |ГДЕ
    |   НЕ Резервы.Регистратор ЕСТЬ NULL";

Этот метод наиболее эффективен, так как он оставляет только строки с реальными движениями. Помните, что проверка Регистратор <> ЗНАЧЕНИЕ(Документ.Имя.ПустаяСсылка) может не сработать, если поле содержит NULL.

Способ 2: Настройка периодичности

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

Посмотрим на правильную установку границ периодов

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


// Вместо использования простой даты, лучше использовать объект Граница
КонецДня = Новый Граница(КонецДня(Объект.ДатаОкончания), ВидГраницы.Включая);
Запрос.УстановитьПараметр("ДатаКон", КонецДня);

Использование Граница с типом Включая гарантирует, что все документы, проведенные в последнюю секунду (23:59:59), попадут в обороты, а не останутся только в конечном остатке следующего периода.

Рассмотрим особенности обработки результата в коде

При обходе результата запроса в языке 1С мы можем дополнительно проверять тип значения в поле регистратора. Проанализируем фрагмент кода:


Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Если ЗначениеЗаполнено(Выборка.Регистратор) Тогда
        // Обрабатываем строку с документом
        Сообщить("Документ: " + Выборка.Регистратор);
    Иначе
        // Это строка с остатками на начало или конец периода
        Сообщить("Начальный остаток по номенклатуре " + Выборка.Номенклатура + ": " + Выборка.НачОстаток);
    КонецЕсли;
КонецЦикла;

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

Выясним причины расхождения данных (Реиндексация)

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

  1. Пересчет итогов: В конфигураторе через "Администрирование — Тестирование и исправление" или через управление итогами в пользовательском режиме.
  2. Проверка актуальности итогов: Убедитесь, что итоги рассчитаны по текущую дату. Виртуальные таблицы работают значительно быстрее и корректнее, когда итоги актуальны.
  3. Реиндексация таблиц: Помогает при физических повреждениях индексов в базе данных SQL или файловом варианте.

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

← На главную