Почему отчет СКД, скопированный из консоли запросов, выводится пустым или некорректно рассчитывает остатки?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем, почему возникают эти проблемы, как устроен внутренний механизм оптимизации СКД и как правильно настроить схему компоновки данных, чтобы ваш отчет работал быстро и выдавал верные цифры.

---

Причина 1. Отсутствие структуры настроек компоновки

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

Выясним причину этого поведения. Когда мы создаем новый отчет в конструкторе СКД с нуля, платформа автоматически генерирует базовую структуру на вкладке «Настройки». Обычно туда помещается стандартная группировка Детальные записи.

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

Решение проблемы:

  1. Перейдем на вкладку «Настройки» в конструкторе схемы компоновки.
  2. В окне «Структура» нажмем правую кнопку мыши и выберем пункт «Добавить» -> «Новая группировка...».
  3. Оставим поле группировки пустым и нажмем «ОК». В структуре появится элемент Детальные записи.
  4. Перейдем на вкладку «Выбранные поля» внизу и перетащим туда все поля, которые должны отображаться в итоговой таблице отчета.

---

Причина 2. Оптимизатор СКД и «исчезновение» полей из временных таблиц

В отличие от обычной консоли запросов, которая выполняет SQL-код «как есть», СКД перед отправкой запроса на сервер СУБД полностью перестраивает его (компонует). Программа анализирует, какие поля выбрал пользователь в настройках, какие отборы применил и какие группировки задействовал.

Если в вашем пакете запросов есть временные таблицы (например, втОстатки, втЗаявлено), которые соединяются между собой по ключевым полям (например, по полю Номенклатура), но само поле Номенклатура не выбрано пользователем в финальных настройках отчета, оптимизатор СКД может посчитать это поле лишним и полностью «вырезать» его из промежуточных запросов во избежание нагрузки на базу данных. Это приведет к разрушению связей между временными таблицами и пустым результатам.

Решение проблемы:

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

---

Причина 3. Неверный расчет и «двоение» остатков (Настройка Ролей)

Это самая распространенная проблема при работе с бухгалтерскими регистрами и регистрами накопления остатков. Автор темы на форуме столкнулся с тем, что при очистке ролей у полей остатков отчет стал работать «правильно», но как только в выборку попало более одного товара, расчет полностью сломался.

Проанализируем, почему это происходит. Поля начального и конечного остатка (например, КоличествоНачальныйОстаток, КоличествоКонечныйОстаток) — это не обычные числовые обороты. Если сложить остаток на понедельник (10 шт.) и остаток на вторник (10 шт.), мы не получим остаток в 20 шт. Остаток на конец периода должен соответствовать значению на последнюю дату, а не сумме за все дни.

Когда мы убираем роли остатков в СКД, система начинает считать их простыми ресурсами и банально суммирует по всем строкам группировок. На выходе получаются огромные, не имеющие отношения к реальности цифры.

Чтобы СКД рассчитывала остатки корректно по всем периодам и иерархиям, выполним по шагам настройку ролей полей на вкладке «Наборы данных»:

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

---

Причина 4. Неоптимальные соединения по составным полям (поле Регистратор)

Рассмотрим фрагмент запроса из сообщения 15 форума:


ИЗ РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный 
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПеремещениеТоваров.Товары КАК ПеремещениеТоваровТовары 
ПО Хозрасчетный.Регистратор = ПеремещениеТоваровТовары.Ссылка

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

Поле Регистратор имеет составной тип данных. При выполнении такого запроса СУБД генерирует внутренние неявные соединения (LEFT JOIN) абсолютно со всеми таблицами документов, которые могут являться регистраторами для данного регистра бухгалтерии.

Как правильно оптимизировать это соединение:

Если мы заранее знаем, что нас интересуют только документы определенного вида (например, ПеремещениеТоваров), мы должны жестко ограничить тип регистратора с помощью конструкции ВЫРАЗИТЬ():


ПО ВЫРАЗИТЬ(Хозрасчетный.Регистратор КАК Документ.ПеремещениеТоваров) = ПеремещениеТоваровТовары.Ссылка

Это позволит СУБД построить оптимальный план запроса и соединить таблицы напрямую, минуя сканирование десятков других таблиц документов.

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

---

Причина 5. Использование предопределенных значений вместо ручной установки параметров

Часто разработчики тратят много времени на написание кода заполнения параметров в модуле формы отчета, как в примере из сообщения 20:


ПараметрСчет = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Счет");
ПараметрСчет.Использование = Истина;
ПараметрСчет.Значение = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;

Этого рутинного шага можно легко избежать. В языке запросов СКД поддерживается обращение к предопределенным элементам конфигурации напрямую через конструкцию ЗНАЧЕНИЕ(). Это избавляет от необходимости писать код заполнения параметров на форме и делает схему отчета полностью автономной.

Заменим передачу параметров в запросе на использование литералов:

Такой подход делает схему компоновки переносимой, чистой и значительно ускоряет разработку и отладку отчета.

← На главную