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