В типовых конфигурациях 1С, построенных на базе Библиотеки Стандартных Подсистем (БСП), таких как Зарплата и управление персоналом 3.1, ERP 2.5 или Управление торговлей 11, дополнительные реквизиты хранятся в табличных частях (например, Справочник.Сотрудники.ДополнительныеРеквизиты). Такая структура удобна для хранения неограниченного количества свойств, но крайне неудобна для построения отчетов, где требуется получить одну строку на каждый объект, а значения реквизитов расположить в отдельных колонках.
Рассмотрим несколько способов решения этой задачи: от динамического построения запроса до использования кросс-таблиц в Системе компоновки данных (СКД).
Попытка написать запрос "в лоб", заранее прописав все возможные колонки, имеет ряд критических недостатков. Проанализируем типичный пример такого решения:
ВЫБРАТЬ
Сотрудники.Ссылка КАК Сотрудник,
МАКСИМУМ(ВЫБОР КОГДА Доп.Свойство = &Свойство1 ТОГДА Доп.Значение КОНЕЦ) КАК Значение1,
МАКСИМУМ(ВЫБОР КОГДА Доп.Свойство = &Свойство2 ТОГДА Доп.Значение КОНЕЦ) КАК Значение2
ИЗ
Справочник.Сотрудники КАК Сотрудники
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК Доп
ПО Сотрудники.Ссылка = Доп.Ссылка
СГРУППИРОВАТЬ ПО
Сотрудники.Ссылка
Почему это плохо:
ВЫБОР.Это программный метод, который позволяет автоматически подстроиться под любое количество дополнительных реквизитов. Суть метода заключается в том, чтобы сначала получить список всех активных свойств для данного типа объекта, а затем в цикле достроить текст запроса.
Разберем алгоритм по шагам:
ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения), которые назначены сотрудникам.Рассмотрим пример кода:
// 1. Получаем список необходимых свойств
ЗапросСвойств = Новый Запрос;
ЗапросСвойств.Текст =
"ВЫБРАТЬ
| Наборы.Свойство КАК Ссылка,
| Наборы.Свойство.Заголовок КАК Заголовок
|ИЗ
| Справочник.НаборыДополнительныхРеквизитовИСведений.ДополнительныеРеквизиты КАК Наборы
|ГДЕ
| Наборы.Ссылка = ЗНАЧЕНИЕ(Справочник.НаборыДополнительныхРеквизитовИСведений.Справочник_Сотрудники)";
РезультатСвойств = ЗапросСвойств.Выполнить().Выгрузить();
// 2. Строим динамический текст запроса
ТекстПолей = "";
ТекстСоединений = "";
Индекс = 0;
Для Каждого Стр Из РезультатСвойств Цикл
ИмяТаблицы = "ДопРеквизит" + Индекс;
ИмяПоля = Стр.Заголовок; // Внимание: здесь нужно очистить имя от спецсимволов
ТекстПолей = ТекстПолей + ", " + ИмяТаблицы + ".Значение КАК " + ИмяПоля;
ТекстСоединений = ТекстСоединений + "
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК " + ИмяТаблицы + "
| ПО Сотрудники.Ссылка = " + ИмяТаблицы + ".Ссылка
| И " + ИмяТаблицы + ".Свойство = &Свойство" + Индекс;
Запрос.УстановитьПараметр("Свойство" + Индекс, Стр.Ссылка);
Индекс = Индекс + 1;
КонецЦикла;
Запрос.Текст = "ВЫБРАТЬ Сотрудники.Ссылка " + ТекстПолей + " ИЗ Справочник.Сотрудники КАК Сотрудники " + ТекстСоединений;
Важный нюанс: SQL Server имеет ограничение на количество таблиц в одном запросе (обычно 256). Если у вас очень много доп. реквизитов, этот метод может вызвать ошибку СУБД. Кроме того, большое количество ЛЕВОЕ СОЕДИНЕНИЕ негативно сказывается на времени выполнения.
Если ваша задача — вывести данные в отчет, то СКД сделает всю "грязную" работу за вас. Это самый производительный и правильный с точки зрения архитектуры способ.
Выясним, как это настроить:
ВЫБРАТЬ
Сотрудники.Ссылка КАК Сотрудник,
ДопРеквизиты.Свойство КАК Свойство,
ДопРеквизиты.Значение КАК Значение
ИЗ
Справочник.Сотрудники КАК Сотрудники
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК ДопРеквизиты
ПО Сотрудники.Ссылка = ДопРеквизиты.Ссылка
Значение. В выражении укажите Максимум(Значение).Сотрудник.Свойство.При формировании отчета СКД автоматически проанализирует все доступные свойства и создаст для каждого из них отдельную колонку. Это работает быстро и не требует написания сложного кода.
В современных конфигурациях 1С реализован программный интерфейс для работы со свойствами. Проанализируем возможности общего модуля УправлениеСвойствами. В нем часто присутствует функционал для динамической модификации текстов запросов.
Например, функция УправлениеСвойствами.ДобавитьДополнительныеРеквизитыВЗапрос позволяет автоматически внедрить в ваш запрос связи с таблицами доп. реквизитов. Это избавляет от необходимости писать велосипеды с циклами по метаданным.
Если данных не слишком много (например, до 5-10 тысяч строк), можно выполнить простой запрос, выгрузить его в ТаблицуЗначений и "развернуть" данные программно в оперативной памяти.
Рассмотрим этот алгоритм:
ТаблицаЗначений.Сотрудник.Свойство добавляем новую колонку в таблицу (если ее еще нет).Найти() или предварительно созданное соответствие.Этот метод часто оказывается быстрее динамического запроса, так как СУБД проще отдать "длинную" таблицу, чем строить "широкую" с сотней соединений.
Поскольку поле Значение в табличной части дополнительных реквизитов имеет составной тип, при выводе в колонки может возникнуть проблема с отображением и сортировкой. Если вы знаете, что реквизит имеет определенный тип (например, Число), в запросе крайне желательно использовать ВЫРАЗИТЬ(Значение КАК ЧИСЛО(15,2)). Это позволит системе корректно обрабатывать данные.
Подведем итог:
УправлениеСвойствами вашей конфигурации.