Почему соединение таблицы ОстаткиИОбороты искажает общие итоги остатков в 1С и как это исправить?

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

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

Рассмотрим, почему при таком подходе сбивается расчет общих итогов по ресурсам остатков и какими способами можно правильно решить эту задачу.

Анализ проблемы и стандартного запроса

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


ВЫБРАТЬ
    Ост.Регистратор КАК Регистратор,
    Ост.Регистратор.МоментВремени КАК МоментВремени,
    Ост.НомерСтроки КАК НомерСтроки,
    Ост.СуммаНачальныйОстаток КАК СН,
    Ост.СуммаОборотДт КАК ДО,
    Ост.СуммаОборотКт КАК КО,
    Ост.СуммаКонечныйОстаток КАК СК,
    Об.КорСчет,
    Об.КорСубконто1
ИЗ
    РегистрБухгалтерии.План.ОстаткиИОбороты(&Дата1, &Дата2, Запись, Движения, Счет = &Счет, , Субконто1 = &Статья) КАК Ост
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрБухгалтерии.План.Обороты(&Дата1, &Дата2, Запись, Счет = &Счет, , Субконто1 = &Статья, , ) КАК Об
    ПО Ост.Регистратор = Об.Регистратор 
   И Ост.НомерСтроки = Об.НомерСтроки
УПОРЯДОЧИТЬ ПО
    МоментВремени,
    Регистратор,
    НомерСтроки
ИТОГИ
    СУММА(СН),
    СУММА(ДО),
    СУММА(КО),
    СУММА(СК)
ПО  ОБЩИЕ,
    Регистратор,
    НомерСтроки

В данном запросе присутствуют сразу две ключевые ошибки, приводящие к неверным результатам:

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

Способы корректного решения задачи

Разберем подробнее варианты построения отчета, которые исключают искажение итоговых сумм по остаткам.

Вариант 1. Использование Системы компоновки данных (СКД)

Наиболее технологичным и рекомендованным решением в платформах 1С:Предприятие является использование СКД. Система компоновки данных умеет корректно рассчитывать нарастающие итоги и вычислять остатки без прямого соединения виртуальных таблиц в тексте запроса.

Для реализации этого подхода выполним следующие шаги:

  1. В наборе данных запроса выбираем движения и обороты из физической таблицы РегистрБухгалтерии.План.ДвижениясСубконто или таблицы Обороты.
  2. В настройках ресурсов на вкладке Ресурсы рассчитываем остатки с помощью встроенных функций СКД.
  3. На вкладке Поля заем ролевые настройки для полей периода: для поля даты укажем роль ПериодСекунда, а для регистратора — Регистратор.
  4. Полям остатков назначаем роли НачальныйОстаток и КонечныйОстаток соответственно.

При таких настройках СКД самостоятельно сформирует оптимальные фоновые запросы для расчета остатков на каждую дату/документ и правильно рассчитает итоговые значения по группировкам без дублирования сумм.

Вариант 2. Предварительная агрегация корреспонденции во временную таблицу

Если отчет необходимо построить простым запросом без использования СКД, требуется гарантировать отношение связей 1-к-1. Для этого сводим детальные записи аналитики во временную таблицу перед окончательным соединением.

Рассмотрим пример алгоритма:


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

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

Благодаря группировке во временной таблице ВТ_Корреспонденция на каждую строку движения приходится строго одна запись. Прямое соединение не разворачивает строки, и стандартный механизм подсчета итогов платформы выдает правильный результат.

Вариант 3. Расчет нарастающего итога в СКД через функцию ВычислитьВыражение

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


ВычислитьВыражение("Сумма(СуммаОборотДт) - Сумма(СуммаОборотКт)", , , "Первая", "Текущая") + &НачальныйОстатокПериода

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

← На главную