При разработке учетных механизмов в платформе 1С:Предприятие начинающие разработчики нередко сталкиваются с ситуацией: запрос к виртуальной таблице остатков или остатков и оборотов либо возвращает пустые поля аналитики, либо отбор по конкретному значению дает пустой результат, хотя движения по регистру существуют. Проанализируем типичную ситуацию на примере регистра взаиморасчетов с водителями, разберем причины такого поведения и выясним, как правильно исправить структуру метаданных и текст запроса.
Рассмотрим исходный фрагмент кода, в котором разработчик пытается получить остатки с фильтрацией по конкретному водителю:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрДепозитВодителяОстаткиИОбороты.Водитель,
| РегистрДепозитВодителяОстаткиИОбороты.ДепозитИтогоКонечныйОстаток,
| РегистрДепозитВодителяОстаткиИОбороты.ДолженВКассуЕЩЕКонечныйОстаток,
| РегистрДепозитВодителяОстаткиИОбороты.СданоВКассуКонечныйОстаток
|ИЗ
| РегистрНакопления.РегистрДепозитВодителя.ОстаткиИОбороты КАК РегистрДепозитВодителяОстаткиИОбороты
|ГДЕ
| РегистрДепозитВодителяОстаткиИОбороты.Водитель = &Водитель";
Запрос.УстановитьПараметр("Водитель", Справочники.Водители.НайтиПоНаименованию("Силкин"));
Результат = Запрос.Выполнить().Выбрать();
При выполнении этого кода выборка оказывается абсолютно пустой. Выясним причину: в конфигураторе для измерения Водитель был ошибочно указан тип ДокументСсылка.СменаВодителей вместо СправочникСсылка.Водители.
В языке запросов 1С сравнение значений разных ссылочных типов не порождает исключительной ситуации. Если в условии сравниваются поля разных типов данных (ссылка на документ и ссылка на справочник), платформа просто вычисляет результат такого выражения как ЛОЖЬ. В результате запрос успешно отрабатывает, но ни одна строка не попадает в итоговую выборку.
Кроме того, если измерением регистра остатков выступает документ, регистр перестает корректно сворачивать итоги по сущности (водителю). Каждая смена формирует свой собственный изолированный остаток, который никогда не закроется другими документами.
Для восстановления корректной работы учета и получения остатков выполним следующие шаги:
Водитель и установим правильный тип: СправочникСсылка.Водители.СменаВодителей).Посмотрим на конструкцию фильтрации в исходном запросе автора. Использование секции ГДЕ при обращении к виртуальным таблицам регистров накопления — грубая ошибка, приводящая к существенному падению производительности.
Когда условие накладывается через ГДЕ, СУБД сначала рассчитывает остатки и обороты по абсолютно всем записям таблицы итогов регистра, и лишь затем отсекает строки, не удовлетворяющие условию. Чтобы выборка работала быстро и использовала штатные индексы базы данных, отбор необходимо передавать во внутренние параметры виртуальной таблицы.
Для таблицы Остатки отбор передается вторым параметром:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрОстатки.Водитель КАК Водитель,
| ПРЕДСТАВЛЕНИЕ(РегистрОстатки.Водитель) КАК ВодительПредставление,
| РегистрОстатки.ДепозитИтогоОстаток КАК ДепозитИтогоОстаток,
| РегистрОстатки.ДолженВКассуЕЩЕОстаток КАК ДолженВКассуЕЩЕОстаток
|ИЗ
| РегистрНакопления.РегистрДепозитВодителя.Остатки(&Период, Водитель = &Водитель) КАК РегистрОстатки";
Запрос.УстановитьПараметр("Период", Новый Граница(ТекущаяДатаСеанса(), ВидГраницы.Включая));
Запрос.УстановитьПараметр("Водитель", ВодительСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(СтрШаблон("Водитель: %1, Депозит: %2, Долг: %3",
Выборка.ВодительПредставление,
Выборка.ДепозитИтогоОстаток,
Выборка.ДолженВКассуЕЩЕОстаток));
КонецЦикла;
Обратим внимание на вызов функции ПРЕДСТАВЛЕНИЕ(). При прямом выводе ссылки в окно сообщений или при конкатенации строк платформа выполняет неявный дополнительный запрос к базе данных для получения наименования. Получение представления непосредственно в запросе исключает лишние серверные вызовы.
Проанализируем состав ресурсов регистра из примера. Наличие ресурсов ДолженВКассуЕЩЕ и СданоВКассу в регистре остатков свидетельствует об ошибке моделирования предметной области:
Сумма. Начисление долга регистрируется приходом, а сдача денег в кассу — расходом. В этом случае положительный остаток по водителю покажет долг водителя перед компанией, а отрицательный — задолженность компании перед водителем (переплату). Для детального анализа поступлений выручки за период следует использовать отдельный регистр накопления с видом «Обороты».