Почему в запросе к остаткам регистра накопления не выводится измерение или не работает отбор?

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

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

Анализ проблемы: несоответствие типов и ошибочная аналитика

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    РегистрДепозитВодителяОстаткиИОбороты.Водитель,
    |    РегистрДепозитВодителяОстаткиИОбороты.ДепозитИтогоКонечныйОстаток,
    |    РегистрДепозитВодителяОстаткиИОбороты.ДолженВКассуЕЩЕКонечныйОстаток,
    |    РегистрДепозитВодителяОстаткиИОбороты.СданоВКассуКонечныйОстаток
    |ИЗ
    |    РегистрНакопления.РегистрДепозитВодителя.ОстаткиИОбороты КАК РегистрДепозитВодителяОстаткиИОбороты
    |ГДЕ
    |    РегистрДепозитВодителяОстаткиИОбороты.Водитель = &Водитель";

Запрос.УстановитьПараметр("Водитель", Справочники.Водители.НайтиПоНаименованию("Силкин"));
Результат = Запрос.Выполнить().Выбрать();

При выполнении этого кода выборка оказывается абсолютно пустой. Выясним причину: в конфигураторе для измерения Водитель был ошибочно указан тип ДокументСсылка.СменаВодителей вместо СправочникСсылка.Водители.

В языке запросов 1С сравнение значений разных ссылочных типов не порождает исключительной ситуации. Если в условии сравниваются поля разных типов данных (ссылка на документ и ссылка на справочник), платформа просто вычисляет результат такого выражения как ЛОЖЬ. В результате запрос успешно отрабатывает, но ни одна строка не попадает в итоговую выборку.

Кроме того, если измерением регистра остатков выступает документ, регистр перестает корректно сворачивать итоги по сущности (водителю). Каждая смена формирует свой собственный изолированный остаток, который никогда не закроется другими документами.

Пошаговое решение проблемы

Для восстановления корректной работы учета и получения остатков выполним следующие шаги:

  1. Изменение типа измерения в конфигураторе. Откроем дерево метаданных, найдем требуемый регистр накопления, перейдем к измерению Водитель и установим правильный тип: СправочникСсылка.Водители.
  2. Обновление конфигурации базы данных. Применим изменения через меню «Конфигурация — Обновить конфигурацию базы данных» (F7).
  3. Перепроведение документов-регистраторов. Это обязательный шаг! При смене типа реквизита или измерения платформа очищает старые несовместимые данные в таблицах движений. Автоматической конвертации документов в элементы справочника не происходит. Чтобы в регистре появились актуальные ссылки на справочник, необходимо программно или вручную заново провести все документы-регистраторы (в нашем случае — документы СменаВодителей).
  4. Проверка пересчета итогов. Если в базе скопился большой массив исторических записей, после массового перепроведения рекомендуется выполнить пересчет итогов регистров накопления через стандартную обработку управления итогами либо через режим «Тестирование и исправление».

Оптимизация запроса: перенос условий в параметры виртуальной таблицы

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

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

Для таблицы Остатки отбор передается вторым параметром:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    РегистрОстатки.Водитель КАК Водитель,
    |    ПРЕДСТАВЛЕНИЕ(РегистрОстатки.Водитель) КАК ВодительПредставление,
    |    РегистрОстатки.ДепозитИтогоОстаток КАК ДепозитИтогоОстаток,
    |    РегистрОстатки.ДолженВКассуЕЩЕОстаток КАК ДолженВКассуЕЩЕОстаток
    |ИЗ
    |    РегистрНакопления.РегистрДепозитВодителя.Остатки(&Период, Водитель = &Водитель) КАК РегистрОстатки";

Запрос.УстановитьПараметр("Период", Новый Граница(ТекущаяДатаСеанса(), ВидГраницы.Включая));
Запрос.УстановитьПараметр("Водитель", ВодительСсылка);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(СтрШаблон("Водитель: %1, Депозит: %2, Долг: %3", 
        Выборка.ВодительПредставление, 
        Выборка.ДепозитИтогоОстаток, 
        Выборка.ДолженВКассуЕЩЕОстаток));
КонецЦикла;

Обратим внимание на вызов функции ПРЕДСТАВЛЕНИЕ(). При прямом выводе ссылки в окно сообщений или при конкатенации строк платформа выполняет неявный дополнительный запрос к базе данных для получения наименования. Получение представления непосредственно в запросе исключает лишние серверные вызовы.

Рекомендации по структуре регистра

Проанализируем состав ресурсов регистра из примера. Наличие ресурсов ДолженВКассуЕЩЕ и СданоВКассу в регистре остатков свидетельствует об ошибке моделирования предметной области:

  1. Разделение остатков и оборотов. Показатель «Сдано в кассу» представляет собой факт хозяйственной деятельности за период (оборот). Если накапливать его в регистре остатков без движений расхода, этот ресурс будет бесконечно расти, приводя к разрастанию таблиц итогов.
  2. Организация учета взаиморасчетов. Для контроля задолженности оптимально использовать классическую схему регистра остатков с одним ресурсом, например Сумма. Начисление долга регистрируется приходом, а сдача денег в кассу — расходом. В этом случае положительный остаток по водителю покажет долг водителя перед компанией, а отрицательный — задолженность компании перед водителем (переплату). Для детального анализа поступлений выручки за период следует использовать отдельный регистр накопления с видом «Обороты».
← На главную