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