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