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