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