Почему в СКД возникает ошибка «Не найден внешний набор данных» и как её исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Причина 1. Передача недопустимого типа данных

Посмотрим на фрагмент кода, в котором выполняется получение данных и их упаковка во внешнюю структуру:


РезЗап = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
ВнешНаб = Новый Структура("НД1", РезЗап);

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

  1. ТаблицаЗначений;
  2. РезультатЗапроса.

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

Для исправления достаточно передавать в структуру сам результат запроса или выгруженную таблицу значений целиком:


// Вариант 1. Передача таблицы значений
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
ВнешНаб = Новый Структура("НД1", ТаблицаДанных);

// Вариант 2. Передача результата запроса напрямую (более экономно по памяти)
РезультатЗапроса = Запрос.Выполнить();
ВнешНаб = Новый Структура("НД1", РезультатЗапроса);

Причина 2. Стандартная обработка не отключена

Вторая распространенная ошибка кроется в обработчике отчета ПриКомпоновкеРезультата. Если мы полностью берем процесс формирования в свои руки (создаем макет, наборы, процессор компоновки и процессор вывода), необходимо в явном виде сообщить платформе, что стандартную генерацию выполнять не нужно.

Если не установить параметр СтандартнаяОбработка = Ложь;, то после выхода из процедуры ПриКомпоновкеРезультата платформа попытается сформировать отчет заново штатным механизмом. При этой повторной компоновке структура ВнешНаб уже не передается, и платформа аварийно завершит работу с той же самой ошибкой: «Не найден внешний набор данных».

Убедимся, что первой строкой процедуры идет отключение стандартной компоновки:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Далее идет программный код формирования...
    
КонецПроцедуры

Причина 3. Несовпадение имени объекта и полей набора

Разберем важную особенность сопоставления наборов данных в СКД. При объявлении объекта набора данных используются два схожих свойства:


НД = СКД.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
НД.Имя = "НД1";
НД.ИмяОбъекта = "НД1";

Важно помнить: поиск соответствия во внешней структуре ВнешНаб платформа выполняет именно по значению свойства ИмяОбъекта, а не Имя. Ключ в структуре должен символ в символ совпадать с тем, что указано в ИмяОбъекта.

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

Причина 4. Пропуск параметров расшифровки

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


МКМ = КМ.Выполнить(СКД, НК);
ПроцессорКомпоновки.Инициализировать(МКМ, ВнешНаб);

При таком подходе в сформированном табличном документе полностью перестанет работать расшифровка ячеек. Чтобы сохранить интерактивность для пользователя, передадим переменную расшифровки в оба метода:


МКМ = КМ.Выполнить(СКД, НК, ДанныеРасшифровки);
ПроцессорКомпоновки.Инициализировать(МКМ, ВнешНаб, ДанныеРасшифровки);

Правильный итоговый вариант программного формирования

Соберем все исправления воедино и посмотрим на корректный и устойчивый вариант процедуры ПриКомпоновкеРезультата:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Формируем массив параметров
    МассПар = Новый Массив;
    Для Каждого Пункт Из ТабличныйПоиск Цикл
        МассПар.Добавить(Пункт);
    КонецЦикла;
    
    // Создаем схему программно
    СКД = Новый СхемаКомпоновкиДанных;
    
    ИД = СКД.ИсточникиДанных.Добавить();
    ИД.Имя = "СхемаСКД";
    ИД.ТипИсточникаДанных = "Local";
    
    НД = СКД.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
    НД.Имя = "НД1";
    НД.ИмяОбъекта = "ТаблицаДанныхДляОтчета";
    НД.ИсточникДанных = "СхемаСКД";
    
    // Добавляем описание полей
    ПНД = НД.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
    ПНД.Поле = "Ссылка";
    ПНД.ПутьКДанным = "Ссылка";
    ПНД.Заголовок = "Изделие";
    
    // Инициализируем настройки схемы
    НК = СКД.НастройкиПоУмолчанию;
    Таб = НК.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
    Таб.Использование = Истина;
    
    ПГКД = Таб.ПоляГруппировки.Элементы.Добавить(Тип("ПолеГруппировкиКомпоновкиДанных"));
    ПГКД.Использование = Истина;
    ПГКД.Поле = Новый ПолеКомпоновкиДанных("Ссылка");
    
    ВП = Таб.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
    ВП.Использование = Истина;
    
    // Выполняем запрос
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Изделие.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Изделие КАК Изделие
        |ГДЕ
        |   Изделие.Ссылка В (&Комплект)";
        
    Запрос.УстановитьПараметр("Комплект", МассПар);
    
    // Выгружаем в ТаблицуЗначений (или передаем РезультатЗапроса)
    ТаблицаДанных = Запрос.Выполнить().Выгрузить();
    
    // Имя ключа структуры строго совпадает с НД.ИмяОбъекта
    ВнешНаб = Новый Структура("ТаблицаДанныхДляОтчета", ТаблицаДанных);
    
    // Компоновка с сохранением расшифровки
    КМ = Новый КомпоновщикМакетаКомпоновкиДанных;
    МКМ = КМ.Выполнить(СКД, НК, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МКМ, ВнешНаб, ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Альтернативный подход: отказ от внешнего набора данных

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

Если перенести исходный запрос прямо в схему компоновки (использовать НаборДанныхЗапрос):

  1. Отпадет необходимость вручную создавать схему, макет и процессоры вывода через встроенный язык.
  2. Значения отборов и списков (&Комплект, &Комплектующие) можно передавать напрямую в параметры компоновщика: КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(...).
  3. Платформа самостоятельно отберет только те поля, которые выводятся в отчет, и корректно обеспечит работу всей стандартной расшифровки без написания дополнительного программного кода.
← На главную