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

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает ситуация, когда один и тот же запрос к виртуальной таблице оборотов регистра накопления или бухгалтерии выдает разные результаты при изменении одного лишь параметра — Периодичность. На первый взгляд это кажется нелогичным: ведь состав данных в регистре не меняется, меняется только детализация. Однако за этим поведением стоит строгая математическая и системная логика работы SQL-запросов, генерируемых платформой.

В этой статье мы подробно разберем, почему итоговые суммы могут «плавать» при переключении между периодичностью Период, Регистратор или при ее отсутствии, и выясним, как правильно накладывать условия, чтобы всегда получать корректные данные.

Механизм формирования виртуальных таблиц

Для начала проанализируем, как система 1С строит виртуальную таблицу. Важно понимать, что в базе данных SQL физически не существует таблицы «Обороты». Есть таблицы движений и таблицы итогов. Когда мы обращаемся к виртуальной таблице в запросе, платформа «на лету» формирует вложенный запрос (subquery), который агрегирует данные.

Рассмотрим два сценария формирования выборки:

  1. Без указания периодичности: Система обращается к физическим таблицам и суммирует все ресурсы (например, СуммаОборот) за указанный период в разрезе выбранных измерений. Если измерения не выбраны вовсе, результатом будет одна-единственная строка с общим итогом.
  2. С периодичностью Регистратор: Система обязана выдать обороты, сгруппированные не только по измерениям, но и по каждому документу, сделавшему запись. В этом случае результатом будет набор строк, где каждая строка соответствует итогу по конкретному регистратору.

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

Влияние условия ГДЕ на результат запроса

Разберем ключевую причину проблемы. В системе 1С условия, прописанные в секции ГДЕ, применяются к результату работы виртуальной таблицы. Это критически важный момент для понимания. Это работает аналогично оператору HAVING в стандартном SQL.

Представим ситуацию: у нас есть два документа.

Проанализируем, что произойдет, если мы напишем запрос с условием ГДЕ СуммаОборот > 0.

Вариант А: Периодичность не указана.
Виртуальная таблица сначала вычислит общий итог: 100 - 20 = 80. Затем сработает условие ГДЕ 80 > 0. Условие истинно, и запрос вернет нам результат: 80.

Вариант Б: Периодичность установлена в значение Регистратор.
Виртуальная таблица выдаст две строки:

  1. Строка 1 (Регистратор №1): Оборот 100.
  2. Строка 2 (Регистратор №2): Оборот -20.
Теперь система применяет условие ГДЕ к каждой строке отдельно. Строка 1 проходит фильтр (100 > 0), а строка 2 — отсекается (-20 не больше 0). В итоге отчет покажет нам сумму: 100.

Таким образом, мы видим разный результат (80 против 100) на одних и тех же данных. Причина — фильтрация сгруппированных данных по ресурсу.

Разница между параметрами виртуальной таблицы и секцией ГДЕ

Для решения подобных проблем крайне важно разделять, где именно накладывается фильтр. Рассмотрим пример правильного и неправильного написания запроса.

Неправильный подход (фильтрация результата):


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

Правильный подход (фильтрация исходных данных):

Если нам нужно отсечь определенные движения еще до их суммирования (например, только движения с видом «Приход»), условие нужно передавать в параметры самой виртуальной таблицы. Это четвертый параметр функции Обороты.


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

В этом случае платформа наложит фильтр непосредственно на записи физической таблицы ВЫБРАТЬ ... ИЗ ... WHERE, и только после этого начнет их группировать. Результат будет математически предсказуемым независимо от выбранной периодичности.

Особенности периодичности Авто

Выясним еще одну важную деталь — использование значения Авто в поле периодичности. Многие разработчики полагают, что это значение «безопасно», но это не так. Периодичность Авто подстраивается под те поля, которые выбраны в секции ВЫБРАТЬ.

Если вы добавите в выборку поле Регистратор или ПериодСекунда, таблица автоматически перейдет в режим детализации по записям. Если же этих полей нет, она вернет общие итоги. Если при этом в запросе присутствует секция ГДЕ с фильтром по суммам, простое добавление поля Регистратор в список колонок может внезапно изменить итоговую сумму в подвале отчета, что часто ставит пользователей в тупик.

Практические рекомендации по работе с запросами

Подведем итог и сформулируем правила, которые помогут избежать ошибок при работе с виртуальными таблицами:

  1. Избегайте условий на ресурсы в секции ГДЕ. Если вам нужно отобрать только положительные обороты, подумайте, не пытаетесь ли вы таким образом отсечь «расходные» документы. Если да — используйте фильтр по измерениям или реквизитам в параметрах виртуальной таблицы.
  2. Параметры ВТ — для фильтрации, ГДЕ — для оформления. Все, что касается логики отбора данных из базы (организация, склад, вид операции), должно быть в параметрах. Секция ГДЕ должна использоваться только в редких случаях для фильтрации уже рассчитанных итогов, понимая последствия группировки.
  3. Проверяйте итоги. Если вы используете периодичность Регистратор, всегда сравнивайте общую сумму с запросом без периодичности. Если они не совпадают — ваше условие ГДЕ работает некорректно.
  4. Используйте Границу. Хотя в обсуждении упоминалось, что Граница не решила проблему (и это логично, так как она влияет на интервал, а не на группировку), хорошим тоном считается использование объекта Граница(КонецПериода, ВидГраницы.Включая) для исключения проблем с попаданием документов, записанных ровно в последнюю секунду периода.

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

← На главную