Как вывести все дополнительные реквизиты объекта 1С в одну строку запроса?

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

В типовых конфигурациях 1С, построенных на базе Библиотеки Стандартных Подсистем (БСП), таких как Зарплата и управление персоналом 3.1, ERP 2.5 или Управление торговлей 11, дополнительные реквизиты хранятся в табличных частях (например, Справочник.Сотрудники.ДополнительныеРеквизиты). Такая структура удобна для хранения неограниченного количества свойств, но крайне неудобна для построения отчетов, где требуется получить одну строку на каждый объект, а значения реквизитов расположить в отдельных колонках.

Рассмотрим несколько способов решения этой задачи: от динамического построения запроса до использования кросс-таблиц в Системе компоновки данных (СКД).

Проблема "статического" запроса

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


ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    МАКСИМУМ(ВЫБОР КОГДА Доп.Свойство = &Свойство1 ТОГДА Доп.Значение КОНЕЦ) КАК Значение1,
    МАКСИМУМ(ВЫБОР КОГДА Доп.Свойство = &Свойство2 ТОГДА Доп.Значение КОНЕЦ) КАК Значение2
ИЗ
    Справочник.Сотрудники КАК Сотрудники
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК Доп
    ПО Сотрудники.Ссылка = Доп.Ссылка
СГРУППИРОВАТЬ ПО
    Сотрудники.Ссылка

Почему это плохо:

  1. Трудоемкость: Если у вас 30 реквизитов, придется вручную прописывать 30 условий ВЫБОР.
  2. Жесткая привязка: При добавлении нового реквизита в пользовательском режиме запрос придется переписывать.
  3. Производительность: При большом количестве данных и сложных группировках такой запрос начинает значительно "тормозить".

Способ 1. Динамическое формирование текста запроса

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

Разберем алгоритм по шагам:

  1. Получаем список всех свойств (элементов ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения), которые назначены сотрудникам.
  2. В цикле формируем строку выбора полей и строку соединений.
  3. Выполняем итоговый запрос.

Рассмотрим пример кода:


// 1. Получаем список необходимых свойств
ЗапросСвойств = Новый Запрос;
ЗапросСвойств.Текст = 
    "ВЫБРАТЬ
    |	Наборы.Свойство КАК Ссылка,
    |	Наборы.Свойство.Заголовок КАК Заголовок
    |ИЗ
    |	Справочник.НаборыДополнительныхРеквизитовИСведений.ДополнительныеРеквизиты КАК Наборы
    |ГДЕ
    |	Наборы.Ссылка = ЗНАЧЕНИЕ(Справочник.НаборыДополнительныхРеквизитовИСведений.Справочник_Сотрудники)";

РезультатСвойств = ЗапросСвойств.Выполнить().Выгрузить();

// 2. Строим динамический текст запроса
ТекстПолей = "";
ТекстСоединений = "";
Индекс = 0;

Для Каждого Стр Из РезультатСвойств Цикл
    ИмяТаблицы = "ДопРеквизит" + Индекс;
    ИмяПоля = Стр.Заголовок; // Внимание: здесь нужно очистить имя от спецсимволов
    
    ТекстПолей = ТекстПолей + ", " + ИмяТаблицы + ".Значение КАК " + ИмяПоля;
    
    ТекстСоединений = ТекстСоединений + "
        | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК " + ИмяТаблицы + "
        | ПО Сотрудники.Ссылка = " + ИмяТаблицы + ".Ссылка 
        | И " + ИмяТаблицы + ".Свойство = &Свойство" + Индекс;
    
    Запрос.УстановитьПараметр("Свойство" + Индекс, Стр.Ссылка);
    Индекс = Индекс + 1;
КонецЦикла;

Запрос.Текст = "ВЫБРАТЬ Сотрудники.Ссылка " + ТекстПолей + " ИЗ Справочник.Сотрудники КАК Сотрудники " + ТекстСоединений;

Важный нюанс: SQL Server имеет ограничение на количество таблиц в одном запросе (обычно 256). Если у вас очень много доп. реквизитов, этот метод может вызвать ошибку СУБД. Кроме того, большое количество ЛЕВОЕ СОЕДИНЕНИЕ негативно сказывается на времени выполнения.

Способ 2. Использование Системы компоновки данных (СКД)

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

Выясним, как это настроить:

  1. Создайте набор данных - запрос, который выбирает сотрудника и его дополнительные реквизиты в "вертикальном" виде (как они лежат в табличной части).

ВЫБРАТЬ
    Сотрудники.Ссылка КАК Сотрудник,
    ДопРеквизиты.Свойство КАК Свойство,
    ДопРеквизиты.Значение КАК Значение
ИЗ
    Справочник.Сотрудники КАК Сотрудники
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК ДопРеквизиты
    ПО Сотрудники.Ссылка = ДопРеквизиты.Ссылка
  1. В закладке "Ресурсы" добавьте поле Значение. В выражении укажите Максимум(Значение).
  2. В закладке "Настройки" выберите тип отчета "Кросс-таблица".
  3. В Строки добавьте поле Сотрудник.
  4. В Колонки добавьте поле Свойство.

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

Способ 3. Механизмы БСП (программный интерфейс)

В современных конфигурациях 1С реализован программный интерфейс для работы со свойствами. Проанализируем возможности общего модуля УправлениеСвойствами. В нем часто присутствует функционал для динамической модификации текстов запросов.

Например, функция УправлениеСвойствами.ДобавитьДополнительныеРеквизитыВЗапрос позволяет автоматически внедрить в ваш запрос связи с таблицами доп. реквизитов. Это избавляет от необходимости писать велосипеды с циклами по метаданным.

Способ 4. Постобработка в Таблице значений

Если данных не слишком много (например, до 5-10 тысяч строк), можно выполнить простой запрос, выгрузить его в ТаблицуЗначений и "развернуть" данные программно в оперативной памяти.

Рассмотрим этот алгоритм:

  1. Выгружаем данные запросом (Сотрудник, Свойство, Значение).
  2. Создаем новую ТаблицаЗначений.
  3. Добавляем колонку Сотрудник.
  4. Обходим результат запроса и для каждого нового Свойство добавляем новую колонку в таблицу (если ее еще нет).
  5. Заполняем значения, используя метод Найти() или предварительно созданное соответствие.

Этот метод часто оказывается быстрее динамического запроса, так как СУБД проще отдать "длинную" таблицу, чем строить "широкую" с сотней соединений.

Рекомендации по типам данных

Поскольку поле Значение в табличной части дополнительных реквизитов имеет составной тип, при выводе в колонки может возникнуть проблема с отображением и сортировкой. Если вы знаете, что реквизит имеет определенный тип (например, Число), в запросе крайне желательно использовать ВЫРАЗИТЬ(Значение КАК ЧИСЛО(15,2)). Это позволит системе корректно обрабатывать данные.

Подведем итог:

← На главную