К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как получить остаток по регистру накопления в 1С

Как получить остаток по регистру накопления в 1С: виртуальная таблица Остатки, запрос на дату, отборы, остатки и обороты, типовые ошибки и проверка результата.

Остаток по регистру накопления в 1С почти всегда получают через виртуальную таблицу «Остатки» (или «ОстаткиИОбороты»), а не перебором физических движений. Платформа сама хранит предрассчитанные итоги, поэтому запрос к виртуальной таблице выполняется быстро даже на больших объёмах данных. Прямой запрос к таблице движений для получения остатка — типичная ошибка, которая приводит к медленной работе и лишней нагрузке на СУБД.

Задача сводится к трём шагам: выбрать нужную виртуальную таблицу, правильно задать период (момент времени, на который считается остаток) и наложить отборы через параметры виртуальной таблицы, а не через секцию ГДЕ. Ниже разобраны все варианты с примерами кода на встроенном языке 1С.

Какие виртуальные таблицы есть у регистра накопления

Регистр накопления вида «Остатки» предоставляет несколько виртуальных таблиц, и выбор между ними определяет и скорость, и корректность результата. Основные варианты:

  • Остатки — остатки на конкретный момент времени (или текущие, если период не указан);
  • ОстаткиИОбороты — начальный остаток, приход, расход и конечный остаток за период;
  • Обороты — только приход и расход за период, без остатков.

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

Запрос к таблице «Остатки»: базовый пример

Простейший вариант — текущие остатки по всем измерениям регистра «ТоварыНаСкладах»:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,

| ТоварыНаСкладахОстатки.Склад КАК Склад,

| ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки";

Результат = Запрос.Выполнить().Выгрузить();

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

Чтобы получить остаток на конкретный момент, передайте первый параметр виртуальной таблицы:

Запрос.Текст =

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК КоличествоОстаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Остатки";

Запрос.УстановитьПараметр("Период", КонецДня(ДатаОтчета));

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

Остаток на дату: тонкости с границами периода

Самая частая ошибка — неверно заданный момент времени. Если передать КонецДня(Дата), документы, проведённые ровно в 23:59:59 этой даты, могут не попасть в остаток, потому что их момент времени больше. Надёжные варианты:

  • передать объект Граница с видом «Включая»: Новый Граница(МоментВремени, ВидГраницы.Включая);
  • использовать конец дня следующего порядка или сознательно брать начало следующего дня с видом «Исключая»;
  • для отчётов на СКД доверить платформе стандартную обработку параметра «Период».
// Остаток на конкретный документ включительно

ГраницаОстатка = Новый Граница(ДокументОбъект.МоментВремени(), ВидГраницы.Включая);

Запрос.УстановитьПараметр("Период", ГраницаОстатка);

Отборы: почему условие ставят в параметры таблицы, а не в ГДЕ

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

Запрос.Текст =

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК КоличествоОстаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";

Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);

В условии виртуальной таблицы допустимы сравнения, В, В ИЕРАРХИИ и логические связки. Но обращаться к полям через точку (например, Номенклатура.ВидНоменклатуры = &Вид) в параметрах виртуальной таблицы нельзя — такие условия выносят в секцию ГДЕ или используют соединение со справочником.

Типичные ошибки
01
Отбор в ГДЕ вместо параметра виртуальной таблицы — остатки считаются по всем измерениям, запрос замедляется в разы
02
Обращение к реквизиту измерения через точку в параметрах таблицы — синтаксическая ошибка запроса
03
Передача даты без границы — документы на границе дня выпадают из остатка
04
Суммирование таблицы движений вместо виртуальной таблицы — лишняя нагрузка и риск неверного результата при отключённых итогах

Остатки и обороты за период

Когда нужен не только остаток, но и движения за период (приход, расход, начальный и конечный остаток), используйте таблицу «ОстаткиИОбороты». У неё четыре параметра: начало периода, конец периода, периодичность и условие.

Запрос.Текст =

"ВЫБРАТЬ

| Данные.Номенклатура КАК Номенклатура,

| Данные.КоличествоНачальныйОстаток КАК НачальныйОстаток,

| Данные.КоличествоПриход КАК Приход,

| Данные.КоличествоРасход КАК Расход,

| Данные.КоличествоКонечныйОстаток КАК КонечныйОстаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&Начало, &Конец, , , ) КАК Данные";

Третий параметр — периодичность (День, Месяц, Регистратор и т.д.). Если указать «Регистратор», в выборке появится поле регистратора и можно будет увидеть, какие документы сформировали обороты. Учтите: чем детальнее периодичность, тем больше строк вернёт запрос.

Сравнение вариантов

Остатки

Нужен только остаток на момент времени. Самый быстрый вариант, минимум полей

ОстаткиИОбороты

Нужны приход/расход за период вместе с остатками. Тяжелее, но заменяет два запроса

Обороты

Остатки не нужны, важны только суммы движений за период

Суммирование движений

Только для специальных задач (например, точность по секундам при отключённых итогах). В обычных случаях не применяйте

Получение остатка в коде: выборка и обход результата

После выполнения запроса результат обычно обрабатывают выборкой или выгрузкой в таблицу значений. Для одиночного остатка (например, проверка «хватит ли товара на складе») удобна выборка:

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

ДоступныйОстаток = Выборка.КоличествоОстаток;

Иначе

ДоступныйОстаток = 0; // записи нет — остатка нет

КонецЕсли;

Важный нюанс: виртуальная таблица не возвращает строк с нулевым остатком. Отсутствие строки означает ноль, и это нужно обрабатывать в коде. Если вы соединяете остатки со списком номенклатуры, используйте ЛЕВОЕ СОЕДИНЕНИЕ и ЕСТЬNULL(Остатки.КоличествоОстаток, 0), иначе позиции без остатка выпадут из результата.

Порядок действий
  1. 1
    Определите, что нужно: только остаток или остаток с оборотами
  2. 2
    Выберите виртуальную таблицу: Остатки или ОстаткиИОбороты
  3. 3
    Задайте период через параметр, при необходимости — через объект Граница
  4. 4
    Вынесите отборы по измерениям во второй параметр таблицы
  5. 5
    Обработайте отсутствие строк как нулевой остаток
  6. 6
    Проверьте результат сверкой с типовым отчётом по регистру

Проверка результата и влияние итогов

Быстрый способ убедиться в корректности — сравнить результат запроса с типовым отчётом (например, «Остатки товаров на складах») на тот же момент и с теми же отборами. Расхождения почти всегда объясняются одной из причин: разная граница периода, разный состав отборов или неактуальные итоги регистра.

Итоги регистра накопления могут быть отключены или рассчитаны не на текущий период — тогда запрос к виртуальной таблице начнёт работать медленно, а при некоторых настройках данные могут отличаться. Проверить состояние итогов можно через методы менеджера регистра: ПолучитьМаксимальныйПериодРассчитанныхИтогов(), ПолучитьИспользованиеТекущихИтогов(). Восстановление итогов выполняется через «Тестирование и исправление» или программно методом ПересчитатьИтоги() — делайте это только на копии или вне рабочего времени, операция ресурсоёмкая.

Контрольные точки

Как проверить результат

Сумма остатка по ключевой позиции
Норма

Совпадает с типовым отчётом на тот же момент

Тревожный признак

Расходится — проверьте границу периода и отборы

Время выполнения запроса
Норма

Доли секунды на выборку с отбором

Тревожный признак

Секунды и больше — отбор в ГДЕ или сбиты итоги

Позиции без остатка
Норма

Показывают 0 через ЕСТЬNULL при левом соединении

Тревожный признак

Позиции пропали из выборки

FAQ

Как получить остаток по конкретной номенклатуре одним числом?

Передайте отбор в параметры виртуальной таблицы: РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Номенклатура = &Номенклатура И Склад = &Склад). Если выборка пустая — остаток равен нулю, обработайте это в коде.

Почему запрос к Остаткам работает медленно?

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

Можно ли получить остаток на дату документа при его проведении?

Да. Передайте в параметр периода объект Граница, построенный на МоментВремени() документа, с видом Включая или Исключая — в зависимости от того, должны ли учитываться движения самого документа.

Чем Остатки отличаются от ОстаткиИОбороты?

Остатки возвращают только конечное сальдо на момент времени. ОстаткиИОбороты дополнительно дают начальный остаток, приход и расход за заданный период, но выполняются дольше и возвращают больше полей.

Почему в результате нет строки, хотя товар был?

Виртуальная таблица не возвращает нулевые остатки: если по комбинации измерений остаток равен нулю, строки не будет. Используйте левое соединение со справочником и функцию ЕСТЬNULL для вывода нулей.

Итог

Что важно запомнить

Остаток по регистру накопления получают через виртуальную таблицу Остатки или ОстаткиИОбороты. Период и отборы передают в параметры таблицы, границу даты задают аккуратно через объект Граница, отсутствие строки трактуют как нулевой остаток. Результат сверяют с типовым отчётом, а при подозрении на проблемы проверяют состояние итогов регистра.