При разработке механизмов контроля лимитов или проверки взаиморасчетов часто возникает задача: получить текущий остаток по регистру так, как будто текущий (уже проведенный или только проводящийся) документ не совершал никаких движений. Типичная ошибка новичков — попытка добавить условие ГДЕ Регистратор <> &Ссылка в запрос к виртуальной таблице. Разберем, почему это не работает, и как решить задачу правильно.
Проанализируем работу виртуальной таблицы ОстаткиИОбороты. Когда мы выбираем периодичность Регистратор, система строит таблицу, где для каждой записи документа рассчитывается остаток. Однако важно понимать: условие ГДЕ в языке запросов 1С применяется к уже готовому результату выборки виртуальной таблицы. Это значит, что если мы исключаем регистратор через ГДЕ, мы просто скрываем строку из отчета, но значения остатков в других строках (на другие даты или по другим документам) останутся прежними, так как они уже были рассчитаны внутри СУБД с учетом всех движений.
Кроме того, в виртуальных таблицах остатков поле Регистратор для итоговых записей может иметь значение NULL (Неопределено), что делает простое сравнение неэффективным. Рассмотрим правильные подходы к решению этой задачи.
Если нам нужно получить остаток «чисто» на момент времени документа (не включая его самого), самым правильным способом будет использование параметра Период в виртуальной таблице Остатки с использованием объекта Граница.
Рассмотрим пример кода на встроенном языке:
ГраницаОстатков = Новый Граница(Объект.Ссылка, ВидГраницы.Исключая);
Запрос.УстановитьПараметр("ПериодОстатков", ГраницаОстатков);
Запрос.Текст = "ВЫБРАТЬ
| Регистр.СуммаОстаток КАК Остаток
|ИЗ
| РегистрНакопления.БюджетыРегионов.Остатки(&ПериодОстатков, ) КАК Регистр";
Использование ВидГраницы.Исключая гарантирует, что движения документа, ссылка на который передана в конструктор, не будут учтены при расчете. Это идеальный вариант для проверок при проведении документа.
Если задача сложнее (например, нужно получить остаток на конец года, но без учета конкретного документа, который находится «внутри» этого года), объект Граница не поможет. В этом случае мы должны применить математический метод: получить общий остаток и вычесть из него влияние конкретного регистратора.
Выясним причину, почему это надежнее: мы оперируем конечными цифрами. Формула проста: РеальныйОстаток = ОбщийОстаток - ПриходДокумента + РасходДокумента. Проанализируем реализацию этого метода в одном запросе:
Запрос.Текст = "ВЫБРАТЬ
| Остатки.Бюджет КАК Бюджет,
| Остатки.СуммаОстаток - ЕСТЬNULL(Движения.СуммаПриход, 0) + ЕСТЬNULL(Движения.СуммаРасход, 0) КАК ОстатокБезДокумента
|ИЗ
| РегистрНакопления.БюджетыРегионов.Остатки(&КонецГода, ) КАК Остатки
| ЛЕВОЕ СОЕДИНЕНИЕ (
| ВЫБРАТЬ
| СуммаПриход КАК СуммаПриход,
| СуммаРасход КАК СуммаРасход
| ИЗ
| РегистрНакопления.БюджетыРегионов.Обороты(,,, Регистратор = &СсылкаТекДокумент)
| ) КАК Движения
| ПО ИСТИНА";
В данном примере мы берем остатки на нужную дату и вычитаем из них вклад текущего документа. Это позволяет получить корректный результат, даже если документ уже проведен и его данные «сидят» в итогах.
В исходном вопросе автор пытался получить обороты по месяцам. Чтобы сделать это корректно и без участия конкретного документа, разберем по шагам следующий алгоритм:
ОстаткиИОбороты с периодичностью МЕСЯЦ.ВЫБОР для корректировки остатка.Посмотрим на пример логики построения такого запроса:
ВЫБРАТЬ
Регистр.Период КАК Месяц,
Регистр.СуммаКонечныйОстаток -
СУММА(ВЫБОР
КОГДА ДопРегистр.Регистратор = &СсылкаТекДокумент
ТОГДА ДопРегистр.СуммаПриход - ДопРегистр.СуммаРасход
ИНАЧЕ 0
КОНЕЦ) КАК СкорректированныйОстаток
ИЗ
РегистрНакопления.БюджетыРегионов.ОстаткиИОбороты(&НачалоГода, &КонецГода, Месяц, , ) КАК Регистр
...
Важный момент: суммирование конечных остатков (СУММА(Регистр.СуммаКонечныйОстаток)), как делал автор темы, является грубой методологической ошибкой. Остаток — это состояние на конкретную дату. Складывать остаток за январь с остатком за февраль нельзя — это приведет к бессмысленным цифрам. Если вам нужно получить остатки за несколько месяцев, используйте итоги по полю Период или Месяц с функцией МАКСИМУМ или просто выводите детальные записи.
Рассмотрим еще один важный нюанс. Использование периодичности Регистратор в больших базах данных может привести к значительным задержкам. Виртуальная таблица вынуждена рассчитывать итоги на каждую секунду, когда была запись в регистре.
Если ваша цель — проверить лимиты, всегда старайтесь ограничить выборку:
ГДЕ. Это позволит SQL-серверу обрабатывать меньше данных.Остатки(&Период, Организация = &Орг И Статья = &Статья).Подведем итог. Чтобы получить остаток без учета документа, мы имеем два надежных пути:
Новый Граница(Ссылка, ВидГраницы.Исключая).Никогда не используйте фильтрацию по регистратору в секции ГДЕ для изменения значений в колонках остатков — это архитектурная особенность платформы 1С, которую нужно просто запомнить.