Почему запрос к виртуальной таблице «Остатки и обороты» не возвращает данные и как правильно получить остатки на начало периода?

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

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

Причина 1: Отсутствие движений в выбранном периоде

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

Рассмотрим, как это решается. В системе компоновки данных (СКД) это настраивается галочкой «Роль -> Период -> Дополнение периодов». Но если мы пишем «чистый» запрос, нам нужно:

  1. Создать временную таблицу со всеми интересующими нас периодами (календарь).
  2. Присоединить к ней таблицу остатков ЛЕВЫМ СОЕДИНЕНИЕМ.

Причина 2: Использование ВНУТРЕННЕГО СОЕДИНЕНИЯ со СрезомПоследних

Посмотрим на этот фрагмент кода автора:


ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ВерсииРасчетов.СрезПоследних(
    &НачалоПланируемогоГода,
    гптэТипГрафикаФИ = ЗНАЧЕНИЕ(Перечисление.гптэТипыГрафикаФИ.ДляБюджета)
) КАК ВерсииРасчетовСрезПоследних
ПО РасчетыСКонтрагентамиГрафикиОстатки.ВерсияГрафика = ВерсииРасчетовСрезПоследних.Регистратор

Здесь кроется критическая ошибка. Если на дату &НачалоПланируемогоГода в регистре сведений нет записи о версии графика для конкретного договора, внутреннее соединение полностью удалит строку с остатком из результата. Выясним причину: ВНУТРЕННЕЕ СОЕДИНЕНИЕ требует обязательного наличия данных в обеих таблицах. Если версия графика была установлена чуть позже или по договору еще нет настроек, остаток «пропадет».

Решение: Всегда используйте ЛЕВОЕ СОЕДИНЕНИЕ при работе со справочными данными или настройками, отсутствие которых не должно приводить к исчезновению финансовых показателей.

Причина 3: Ошибка логики расчета нарастающего итога

Проанализируем финальную часть запроса автора:


ЛЕВОЕ СОЕДИНЕНИЕ Движения КАК Движения
ПО (Движения.Период < Месяца.Период)

Автор пытается вычислить остаток на начало месяца путем сложения всех предыдущих движений. Это классический подход SQL для расчета нарастающего итога, но он требует обязательной группировки. Без конструкции СГРУППИРОВАТЬ ПО и агрегатной функции СУММА(Движения.СуммаОборот) такой запрос порождает декартово произведение. Каждая строка месяца соединяется с каждой строкой движения, что приводит к геометрическому росту количества строк и неверным цифрам.

Как сделать правильно: алгоритм получения остатков помесячно

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

Шаг 1: Подготовка периодов. Сначала создадим временную таблицу, содержащую все начала месяцев в выбранном интервале.


ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&НачалоПериода, МЕСЯЦ, Номера.Номер - 1) КАК Период
ПОМЕСТИТЬ ВсеМесяцы
ИЗ
    (ВЫБРАТЬ 1 КАК Номер ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ... ВЫБРАТЬ 12) КАК Номера
ГДЕ
    Номера.Номер <= РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, МЕСЯЦ) + 1
;

Шаг 2: Получение данных из виртуальной таблицы. Важно передавать условия фильтрации (по ЦФО, договору) непосредственно в параметры виртуальной таблицы, а не в секцию ГДЕ. Это значительно ускоряет работу и гарантирует корректность расчета итогов.


ВЫБРАТЬ
    Регистр.Период КАК Период,
    Регистр.ПредметГрафика КАК Договор,
    Регистр.СуммаНачальныйОстаток КАК ОстатокНаНачало,
    Регистр.СуммаОборот КАК ОборотЗаМесяц
ПОМЕСТИТЬ ДанныеРегистра
ИЗ
    РегистрНакопления.РасчетыСКонтрагентамиГрафики.ОстаткиИОбороты(
        &НачалоПериода, 
        &КонецПериода, 
        Месяц, , 
        ЭлементСтруктурыЗадолженности = &ОсновнойДолг
    ) КАК Регистр
;

Шаг 3: Соединение с дополнением. Теперь соединим таблицу всех месяцев с данными регистра. Используем ЛЕВОЕ СОЕДИНЕНИЕ от таблицы месяцев, чтобы не потерять периоды без активности.


ВЫБРАТЬ
    ВсеМесяцы.Период КАК Период,
    Данные.Договор КАК Договор,
    ЕСТЬNULL(Данные.ОстатокНаНачало, 0) КАК Сумма
ИЗ
    ВсеМесяцы КАК ВсеМесяцы
    ЛЕВОЕ СОЕДИНЕНИЕ ДанныеРегистра КАК Данные
    ПО ВсеМесяцы.Период = Данные.Период

Важные технические нюансы

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

← На главную