При разработке отчетов в системе компоновки данных (СКД) на базе регистра бухгалтерии разработчики нередко сталкиваются с ситуацией, когда запрос к виртуальной таблице оборотов перестает возвращать данные при добавлении условий или дополнительных полей. Разберем типичные причины такого поведения, проанализируем реальный практический пример и рассмотрим способы оптимизации запросов к бухгалтерским итогам.
Рассмотрим исходный текст запроса к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.Обороты, в котором возникла проблема отсутствия строк:
ВЫБРАТЬ
ХозрасчетныйОбороты.СуммаОборотДт КАК Себестоимость,
ХозрасчетныйОбороты.Субконто2.ДоговорКонтрагента.Полуфабрикат КАК Полуфабрикат,
ХозрасчетныйОбороты.Регистратор КАК ДокументПоступления
ПОМЕСТИТЬ СебестоимостьПолуфабрикатов
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(
&НачалоПериода,
&КонецПериода,
Регистратор,
Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ОсновноеПроизводство),
,
,
КорСчет В (&КоррСчета),
) КАК ХозрасчетныйОбороты;
При выполнении этого запроса без фильтра по КорСчет данные выбирались, но при включении отбора КорСчет В (&КоррСчета) результат становился пустым. Кроме того, при соединении временных таблиц строки пропадали полностью. Выясним причину этой проблемы и рассмотрим по шагам, как исправить логику запроса.
Проанализируем выражение ХозрасчетныйОбороты.Субконто2.ДоговорКонтрагента.Полуфабрикат. В типовом плане счетов Хозрасчетный для счета 20.01 («Основное производство») вторым субконто чаще всего является справочник Статьи затрат или Подразделения, у которых нет реквизита ДоговорКонтрагента.
Когда мы обращаемся через точку к несуществующему реквизиту объекта или пытаемся получить реквизит через поле неподходящего типа, платформа 1С возвращает значение NULL. Если в дальнейшем результирующая временная таблица соединяется по этому полю с другой таблицей через условие ПО Таблица1.Полуфабрикат = Таблица2.Полуфабрикат, строки отсекаются из-за сравнения с NULL.
В данном случае требуемый реквизит находился в самом документе-регистраторе, а не в аналитике счета. Исправим обращение к полю:
ХозрасчетныйОбороты.Регистратор.ДоговорКонтрагента.Полуфабрикат КАК Полуфабрикат
Разберем, почему отбор КорСчет В (&КоррСчета) может возвращать пустой результат, даже если проводки с нужными счетами в базе присутствуют:
В: Если в список значений &КоррСчета передан счет-родитель (например, 10 или 60), для которого установлен признак «Запретить использовать в проводках», прямое условие КорСчет В (&КоррСчета) не вернет движения по его субсчетам (10.07, 60.01). Чтобы учесть всю иерархию, необходимо использовать конструкцию КорСчет В ИЕРАРХИИ (&КоррСчета).Список значений с элементами типа ПланСчетовСсылка.Хозрасчетный, а не одиночная ссылка или строковое значение.ЗНАЧЕНИЕ, что исключает ошибки передачи параметров:
КорСчет В (
ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.МатериалыПереданныеВПереработку),
ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.РасчетыСПоставщиками)
)
Поле Регистратор в регистре бухгалтерии имеет составной тип данных, включающий множество видов документов. Прямое обращение через точку вида Регистратор.ДоговорКонтрагента заставляет СУБД генерировать неявные левые соединения (LEFT JOIN) со всеми таблицами документов конфигурации, способными делать движения по регистру. Это приводит к сильному падению производительности.
Для оптимизации запроса применим оператор явного приведения типа ВЫРАЗИТЬ:
ВЫРАЗИТЬ(
ХозрасчетныйОбороты.Регистратор КАК Документ.ПоступлениеИзПереработки
).ДоговорКонтрагента.Полуфабрикат КАК Полуфабрикат
Объединим все исправления: используем явное приведение типа для регистратора, корректное условие для корреспондирующих счетов и безопасное левое соединение с функцией ЕСТЬNULL для исключения пустых значений:
ВЫБРАТЬ
ХозрасчетныйОбороты.СуммаОборотДт КАК Себестоимость,
ВЫРАЗИТЬ(
ХозрасчетныйОбороты.Регистратор КАК Документ.ПоступлениеИзПереработки
).ДоговорКонтрагента.Полуфабрикат КАК Полуфабрикат,
ХозрасчетныйОбороты.Регистратор КАК ДокументПоступления
ПОМЕСТИТЬ СебестоимостьПолуфабрикатов
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(
&НачалоПериода,
&КонецПериода,
Регистратор,
Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ОсновноеПроизводство),
,
,
КорСчет В ИЕРАРХИИ (&КоррСчета),
) КАК ХозрасчетныйОбороты;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
КоличествоПолуфабрикатов.Полуфабрикат КАК Полуфабрикат,
КоличествоПолуфабрикатов.ДокументПоступления КАК ДокументПоступления,
СУММА(КоличествоПолуфабрикатов.КоличествоПолуфабриката) КАК КоличествоПолуфабриката,
ВозвратныеОтходы.ВозвратныйОтход КАК ВозвратныйОтход,
СУММА(ВозвратныеОтходы.СтоимостьПринятия) КАК СтоимостьПринятия,
СУММА(
ЕСТЬNULL(СебестоимостьПолуфабрикатов.Себестоимость, 0) - ЕСТЬNULL(ВозвратныеОтходы.СтоимостьПринятия, 0)
) КАК СебестоимостьПолуфабриката
ИЗ
КоличествоПолуфабрикатов КАК КоличествоПолуфабрикатов
ЛЕВОЕ СОЕДИНЕНИЕ ВозвратныеОтходы КАК ВозвратныеОтходы
ПО КоличествоПолуфабрикатов.ДокументПоступления = ВозвратныеОтходы.ДокументПоступления
ЛЕВОЕ СОЕДИНЕНИЕ СебестоимостьПолуфабрикатов КАК СебестоимостьПолуфабрикатов
ПО КоличествоПолуфабрикатов.Полуфабрикат = СебестоимостьПолуфабрикатов.Полуфабрикат
И КоличествоПолуфабрикатов.ДокументПоступления = СебестоимостьПолуфабрикатов.ДокументПоступления
СГРУППИРОВАТЬ ПО
КоличествоПолуфабрикатов.Полуфабрикат,
КоличествоПолуфабрикатов.ДокументПоступления,
ВозвратныеОтходы.ВозвратныйОтход;
Для того чтобы отчет работал гибко и не возвращал пустой результат при незаполненных параметрах в пользовательском режиме, рекомендуется использовать расширение языка запросов СКД с фигурными скобками:
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(
&НачалоПериода,
&КонецПериода,
Регистратор,
{Счет.* КАК Счет},
,
,
{КорСчет.* КАК КорСчет},
) КАК ХозрасчетныйОбороты
При таком подходе СКД автоматически добавит условие в параметры виртуальной таблицы только в том случае, если пользователь установил соответствующий отбор в настройках отчета.