Как решить проблемы с лишними полями и невыводимыми группировками в отчетах на СКД 1С?

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

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

СКД — это мощный, но иногда "самостоятельный" инструмент, который стремится помочь нам, но порой делает это не совсем так, как мы ожидаем. Понимание его логики и правильные методы отладки помогут нам взять компоновку данных под полный контроль.

Проблема 1: Присутствуют поля, которых не должно быть в отчете СКД

Одна из первых загадок, с которой мы сталкиваемся, – это появление в списке доступных полей СКД элементов, которые мы не указывали в тексте запроса. Это может сбивать с толку и усложнять работу, даже если не приводит к прямым ошибкам.

Почему СКД выдает лишние поля?

Система Компоновки Данных спроектирована таким образом, чтобы максимально упростить жизнь пользователю и предоставить ему широкий спектр возможностей для настройки отчетов. Именно это "усердие" СКД часто приводит к появлению нежелательных полей. Рассмотрим основные причины:

  1. Автозаполнение СКД: Если при создании или изменении набора данных запроса мы оставляем включенным флажок "Автозаполнение" (что является поведением по умолчанию), СКД автоматически добавляет в список доступных полей компоновки данных все поля, которые она может определить на основе вашего запроса, а также реквизиты ссылочных типов. Это удобно для быстрых отчетов, но может привести к избыточности и путанице, если вы вручную настраиваете поля.
  2. Подчиненные поля и реквизиты ссылочных типов: СКД "умно" предвидит, что вам могут понадобиться детализация по ссылочным полям. Если в запросе выбрано поле ссылочного типа, например, ЗаказПр (ссылка на документ "Заказ на производство"), СКД автоматически добавит в список доступных полей его реквизиты, такие как ЗаказПр.Номер, ЗаказПр.Дата, ЗаказПр.Контрагент и т.д. Это происходит, даже если мы явно не указали эти реквизиты в нашем тексте запроса. СКД делает это, чтобы мы могли использовать их в отборах, группировках или для вывода, не модифицируя запрос.
  3. Параметры виртуальных таблиц: Некоторые параметры, которые мы передаем в виртуальные таблицы (например, НачалоПериода, КонецПериода для таблиц остатков и оборотов регистров), также могут быть автоматически добавлены в список доступных полей или параметров СКД, даже если они не были явно выбраны в запросе или настроены как параметры компоновки данных.
  4. Дублирование полей: Если мы в запросе переименовали какое-либо поле (например, Номенклатура стала Товар), но автозаполнение включено, СКД может попытаться добавить как новое, переименованное поле, так и исходное (если оно все еще может быть вычислено из базовых таблиц), создавая дубли.

Как побороть лишние поля в СКД?

Для того чтобы взять контроль над списком полей и избежать нежелательных элементов, мы можем предпринять несколько шагов:

  1. Отключение автозаполнения: Это основной и самый эффективный метод. * Откройте схему компоновки данных в конфигураторе. * Перейдите на вкладку "Наборы данных". * Выберите ваш набор данных (запрос). * Снимите флажок "Автозаполнение" в свойствах набора данных. * После этого перейдите на вкладку "Поля" и вручную добавьте все поля, которые нам действительно нужны для отчета, прямо из запроса. Этот подход дает нам полный контроль над тем, что будет доступно в отчете.
  2. Использование фигурных скобок {} в запросе: Для более тонкой настройки доступных полей в СКД, мы можем использовать расширение языка запросов, заключая необходимые поля в фигурные скобки. СКД будет работать только с полями, заключенными в {}.
    
    ВЫБРАТЬ
        {ВЫБОР
            КОГДА ЗаказПр.Контрагент = &МойКонтрагент ТОГДА ЗаказПр.Номер
            ИНАЧЕ "Другой"
        КОНЕЦ КАК НомерЗаказа},
        {ЗаказПр.Дата КАК ДатаЗаказа},
        {ЗаказПр.Сумма КАК СуммаДокумента}
    ИЗ
        Документ.ЗаказНаПроизводство КАК ЗаказПр
    

    Используя этот синтаксис, мы явно указываем СКД, какие поля должны быть доступны, игнорируя другие потенциальные реквизиты.

  3. Установка признака "Обязательное" для полей: В некоторых случаях, когда поле отсутствует в результате запроса (например, из-за условий соединения), но нам нужно, чтобы оно присутствовало в списке полей СКД (например, для использования в условном оформлении), мы можем установить для него признак "Обязательное" на вкладке "Поля" набора данных.

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

Вторая распространенная проблема, которая вызывает замешательство, – это когда поле, явно присутствующее в запросе и не скрытое в настройках, отказывается выводиться в отчете, особенно при использовании в качестве поля группировки.

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

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

  1. Некорректный тип данных поля:
    • Строка неограниченной длины: Это наиболее часто упоминаемая причина. СКД не может корректно работать с группировками по полям типа "Строка неограниченной длины". Если наше поле является результатом выражения, которое может вернуть такой тип, или является текстовым полем базы данных без явного ограничения длины, оно не будет выводиться в группировке.
    • Смешанный тип данных в выражении ВЫБОР: Если мы формируем поле с помощью оператора ВЫБОР, и различные ветви этого оператора возвращают значения разных типов, СКД может некорректно определить результирующий тип для поля. Например, если в одном случае возвращается Дата, в другом – СсылкаНаСправочник, а в третьем – просто Строка, СКД может "потеряться" и посчитать такое поле непригодным для группировки.
      
      ВЫБОР
          КОГДА Поле1 = Истина ТОГДА ПолеДаты
          КОГДА Поле2 = Истина ТОГДА ПолеСправочникаСсылка
          ИНАЧЕ "Неопределено"
      КОНЕЦ
      

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

  2. Несоответствие поля группировки и выбранных полей: Ошибка "поле не может быть использовано в группировке" может возникать, если мы пытаемся сгруппировать по полю, которое:
    • Не является собственно полем группировки, явно указанным в настройках.
    • Не является полем одной из вышестоящих группировок.
    • Не является дочерним полем одной из группировок (например, реквизитом ссылки, по которой уже есть группировка).
  3. Функциональные опции и права доступа: Иногда поле может не отображаться в отчете из-за настроек функциональных опций конфигурации или ограничений прав доступа. Даже при полных правах, функциональные опции могут динамически скрывать поля или целые разделы отчетов.
  4. Специфика "Детальных записей": Если у нас есть группировка "Детальные записи" (т.е. без указанных полей группировки) и в списке выбранных полей присутствуют только ресурсы (например, суммы, количества), то такая группировка может быть интерпретирована как "общий итог". В этом случае СКД может вывести только одну строку с итоговыми значениями по выбранным ресурсам, скрывая детальные поля, если они не являются ресурсами.
  5. Наследование настроек: Подчиненные группировки наследуют список выбранных полей и параметры сортировки от родительской группировки, если в их настройках указан элемент "Авто". Это может привести к тому, что в подчиненной группировке будут выводиться не те поля, которые мы ожидаем, или не выводиться вовсе.
  6. Поля, не указанные как группировочные в конфигураторе: В некоторых, более сложных случаях, особенно при работе с характеристиками или дополнительными реквизитами, поля могут выводиться в отчет, но не быть доступными для группировки, если они не были явно указаны в настройках СКД в конфигураторе как возможные поля для группировки.

Как добиться вывода поля в группировке?

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

  1. Явное приведение типа данных с помощью ВЫРАЗИТЬ():

    Это критически важное решение для полей, которые формируются через оператор ВЫБОР или могут иметь неопределенный тип. Нам нужно явно указать СКД, какой тип данных и какой длины должно быть результирующее поле.

    Пример проблемного поля из нашей темы выглядел так:

    
    ВЫБОР
        КОГДА взЗаказНаПроизводствоПотоки.Поток = &Фасады
            И взЗаказНаПроизводствоПотоки.ГруппаМаршрута = &ГруппаМаршрутаЭмаль
            ТОГДА ВЫБОР
                КОГДА ПотокиЗаказа.Размещение = &ГотоваяПродукция
                    ТОГДА ПотокиЗаказа.Период
                КОГДА НЕ ПотокиЗаказа.Размещение ЕСТЬ NULL
                    И НЕ ПотокиЗаказа.Размещение = НЕОПРЕДЕЛЕНО
                    ТОГДА ПотокиЗаказа.Размещение
                ИНАЧЕ &НеВзятВРаботу
            КОНЕЦ
        ИНАЧЕ "-"
    КОНЕЦ
    

    Здесь мы видим, что внутренний ВЫБОР может вернуть либо Период (тип "Дата"), либо Размещение (тип "Ссылка на Справочник.МестаРазмещения"), либо &НеВзятВРаботу (тип "Строка"). Внешний ВЫБОР добавляет еще один строковый вариант "-". СКД не может однозначно определить тип такого поля для целей группировки.

    Чтобы решить эту проблему, нам необходимо явно привести все возможные результаты к одному типу, например, СТРОКА, с указанием конкретной длины:

    
    ВЫРАЗИТЬ(ВЫБОР
        КОГДА взЗаказНаПроизводствоПотоки.Поток = &Фасады
            И взЗаказНаПроизводствоПотоки.ГруппаМаршрута = &ГруппаМаршрутаЭмаль
            ТОГДА ВЫБОР
                КОГДА ПотокиЗаказа.Размещение = &ГотоваяПродукция
                    ТОГДА ПотокиЗаказа.Период
                КОГДА НЕ ПотокиЗаказа.Размещение ЕСТЬ NULL
                    И НЕ ПотокиЗаказа.Размещение = НЕОПРЕДЕЛЕНО
                    ТОГДА ПотокиЗаказа.Размещение
                ИНАЧЕ &НеВзятВРаботу
            КОНЕЦ
        ИНАЧЕ "-"
    КОНЕЦ КАК СТРОКА(50)) КАК ФасадыЭмаль
    

    Здесь мы используем ВЫРАЗИТЬ(... КАК СТРОКА(50)). Важно указать не просто СТРОКА, а СТРОКА(N), где N – это максимальная ожидаемая длина строки. СКД не любит строки неограниченной длины для группировок. Даже если поле в базе данных является строкой неограниченной длины, приведение его к строке ограниченной длины в запросе СКД может решить проблему.

  2. Тщательная проверка настроек группировки:
    • Откройте настройки отчета и перейдите на вкладку "Структура".
    • Убедитесь, что в выбранных полях группировки указано именно то поле, по которому должна выполняться группировка.
    • Избегайте использования "Автополе", если нам нужна точная настройка вывода, и вручную укажите список выводимых полей для каждой группировки.
  3. Использование пользовательских полей:

    Если прямое приведение типа в запросе не помогает, мы можем попробовать создать пользовательское поле в СКД (на вкладке "Наборы данных" -> "Поля" -> "Пользовательские поля"). В нем мы можем написать выражение, которое вычисляет нужное значение и явно приводит его к строке. Однако, как показывает опыт, если проблема связана с глубоким непониманием СКД типа поля, пользовательские поля могут также не дать желаемого результата, так как они работают поверх уже сформированного набора данных СКД.

  4. Детальная отладка СКД в ПриКомпоновкеРезультата:

    Это самый мощный инструмент диагностики, когда стандартные методы не помогают. Мы можем программно получить и проанализировать запрос, который СКД в итоге формирует и выполняет. Это поможет нам понять, что происходит с нашим проблемным полем на промежуточных этапах формирования макета.

    Разберем по шагам, как это сделать в обработчике события ПриКомпоновкеРезультата:

    1. Мы перехватываем стандартную обработку компоновки.
    2. Инициализируем компоновщик макета и выполняем его для получения макета компоновки данных.
    3. Из полученного макета извлекаем наш набор данных (запрос).
    4. Получаем и выводим в сообщения текст запроса, который СКД сформировала.
    5. Анализируем этот текст запроса: присутствует ли наше поле, какой у него тип, не изменила ли СКД что-то в его формировании.

    Пример кода для отладки в модуле отчета:

    
    Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
        // Отключаем стандартную обработку, чтобы вручную скомпоновать отчет
        СтандартнаяОбработка = Ложь;
    
        // Создаем компоновщик макета компоновки данных
        КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
        // Выполняем компоновку для получения макета
        МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
    
        // --- БЛОК ДЛЯ ОТЛАДКИ ЗАПРОСА ---
        // Предполагаем, что у нас один набор данных в схеме.
        // Если наборов данных несколько, нужно выбрать нужный по индексу или имени.
        Если МакетКомпоновки.НаборыДанных.Количество() > 0 Тогда
            НаборДанныхЗапроса = МакетКомпоновки.НаборыДанных[0]; 
            Если НаборДанныхЗапроса.Тип = Тип("НаборДанныхЗапрос") Тогда
                // Получаем текст запроса, который будет выполнен
                ТекстЗапроса = НаборДанныхЗапроса.Запрос;
                // Выводим текст запроса в сообщения, чтобы его проанализировать
                Сообщить("Сформированный СКД запрос:" + Символы.ПС + ТекстЗапроса); 
                        
                // Здесь мы можем дополнительно проверить свойства поля в МакетКомпоновки.Поля
                // или МакетКомпоновки.НаборыДанных[0].Поля
                // Например, чтобы узнать определенный СКД тип поля:
                Для Каждого ПолеМакета Из НаборДанныхЗапроса.Поля Цикл
                    Если ПолеМакета.Имя = "ФасадыЭмаль" Тогда // Проблемное поле из примера
                        Сообщить("Поле 'ФасадыЭмаль' в макете имеет тип: " + ПолеМакета.Тип.Имя);
                        Сообщить("Поле 'ФасадыЭмаль' в макете имеет длину: " + Строка(ПолеМакета.Длина));
                        Прервать;
                    КонецЕсли;
                КонецЦикла;
            КонецЕсли;
        КонецЕсли;
        // --- КОНЕЦ БЛОКА ДЛЯ ОТЛАДКИ ЗАПРОСА ---
    
        // Создаем процессор компоновки данных и инициализируем его
        ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
        ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
        // Создаем процессор вывода результата компоновки данных в табличный документ
        ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
        ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    
        // Начинаем вывод результата
        ПроцессорВывода.НачатьВывод();
        Пока Истина Цикл
            ЭлементРезультата = ПроцессорКомпоновки.Следующий();
            Если ЭлементРезультата = Неопределено Тогда
                Прервать;
            Иначе
                ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
            КонецЕсли;
        КонецЦикла;
        ПроцессорВывода.ЗакончитьВывод();
    КонецПроцедуры
    

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

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

← На главную