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