Как связать внешний набор данных (ТаблицаЗначений) с запросом в СКД при работе через COM-соединение

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

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

Постановка задачи и получение внешних данных

Представим ситуацию: нам нужно получить данные по пробегу автомобилей (спидометр) из внешней базы «Управление автотранспортом» (УАТ) и связать их с данными о водителях в нашей текущей базе. В качестве связующего поля используется ФИО водителя (тип Строка).

Первым делом нам необходимо установить соединение с внешней базой и выполнить запрос. Рассмотрим пример кода, который подготавливает внешнюю таблицу значений (ТЗ) для передачи в СКД. Важно помнить, что при работе через COM-соединение прямое обращение к свойствам объектов (например, Результат.Водитель1.Наименование) внутри цикла работает крайне медленно, так как вызывает обращение к другой базе на каждой итерации. Правильнее получать представление или наименование прямо в тексте запроса.

Проанализируем правильный подход к заполнению таблицы значений:


// В модуле объекта отчета (ПриКомпоновкеРезультата)
Соединение = Новый COMОбъект("v82.Application");
Параметры = "Srvr=""192.168.32.59:4556"";Ref=""uat"";Usr=""User"";Pwd=""12345"";";

Попытка
    Подключение = Соединение.Connect(Параметры);
Исключение
    Сообщить("Не удалось подключиться к базе: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

ЗапросCOM = Соединение.NewObject("Запрос"); 
ЗапросCOM.Текст = "ВЫБРАТЬ
                 |  СУММА(уатПутевойЛист.СпидометрВыезда) КАК СпидометрВыезда,
                 |  СУММА(уатПутевойЛист.СпидометрВозвращения) КАК СпидометрВозвращения,
                 |  уатПутевойЛист.Водитель1.Наименование КАК ВодительНаименование
                 | ИЗ
                 |  Документ.уатПутевойЛист КАК уатПутевойЛист
                 | СГРУППИРОВАТЬ ПО
                 |  уатПутевойЛист.Водитель1.Наименование";

РезультатЗапроса = ЗапросCOM.Выполнить().Выбрать();

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("СпидометрВыезда", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("СпидометрВозвращения", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("Водитель1", Новый ОписаниеТипов("Строка"));

Пока РезультатЗапроса.Следующий() Цикл
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.СпидометрВыезда = РезультатЗапроса.СпидометрВыезда;
    НоваяСтрока.СпидометрВозвращения = РезультатЗапроса.СпидометрВозвращения;
    // Используем уже полученную строку наименования, чтобы избежать COM-вызовов
    НоваяСтрока.Водитель1 = РезультатЗапроса.ВодительНаименование;
КонецЦикла;

Настройка связи наборов данных в схеме СКД

После того как данные получены, необходимо правильно настроить Набор данных - объект в схеме СКД. Рассмотрим важные шаги:

  1. Создадим второй набор данных с типом Набор данных - объект.
  2. В поле Имя объекта содержащего данные укажем строку (например, "ВнешниеДанныеТЗ"). Именно это имя будет использоваться в коде при инициализации процессора компоновки.
  3. Добавим поля набора данных: СпидометрВыезда (Число), СпидометрВозвращения (Число), Водитель1 (Строка). Важно: имена полей должны строго совпадать с именами колонок в нашей ТаблицеЗначений.

Перейдем на вкладку Связи наборов данных. Выясним причину, по которой отчет может быть пуст при использовании связей:

Связи в СКД работают по принципу Left Join (Левое соединение). Если первый набор (основной) не содержит записей, которые есть во втором наборе, то данные из второго набора не появятся. Если же ваша цель — увидеть всех водителей, даже если их нет в основной базе, рассмотрите использование типа Объединение вместо Связи.

Если используется связь, обратите внимание на выражения:

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

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

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


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

Анализ типичных ошибок

Рассмотрим подробнее, почему связь может не работать:

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

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

← На главную