Как отсортировать справочник по ссылочному реквизиту и году рождения в 1С:Предприятие 8?

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

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

В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем внутренние механизмы работы платформы 1С и рассмотрим два практических способа решения задачи: простой учебный метод с использованием Таблицы Значений и профессиональный оптимальный метод с использованием Языка запросов 1С.

Выясняем причину: почему метод Выбрать() выдает ошибку?

Попытка вызвать метод выборки в коде следующим образом:

Выборка = Справочники.Сотрудники.Выбрать(,,,"ФилиалРаботы");

Вызовет системную ошибку: «Выборка может быть упорядочена только по реквизитам, имеющим базовый тип и для которых установлен признак индексирования». Давайте разберем, почему это происходит:

  1. Ограничение по типам данных: Метод Выбрать() умеет выполнять сортировку силами СУБД только по полям простых (базовых) типов. К ним относятся Строка, Число, Дата и Булево. Реквизит ФилиалРаботы имеет тип ссылки (например, СправочникСсылка.Филиалы), который не является базовым.
  2. Требование индексации: Для того чтобы платформа могла упорядочить выборку по какому-либо реквизиту базового типа, у этого реквизита в Конфигураторе должно быть включено свойство «Индексировать» или «Индексировать с дополнительным упорядочиванием».
  3. Сортировка по уникальному идентификатору (UUID): Даже если бы платформа позволила отсортировать данные по ссылке напрямую, СУБД выстроила бы элементы в порядке их внутренних уникальных идентификаторов (GUID). Для конечного пользователя такой порядок выглядел бы хаотичным и бессмысленным, так как он не совпадает ни с алфавитным порядком наименований, ни с кодами элементов.

---

Решение 1. Использование временной Таблицы Значений (Объектная модель)

Если вы только начинаете изучать программирование в 1С и еще не освоили язык запросов, решить задачу можно с помощью выгрузки данных во временную таблицу значений (ТЗ) с её последующей сортировкой. Этот способ отлично подходит для понимания объектной модели платформы.

Рассмотрим пошагово, как реализовать этот алгоритм:

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

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


// Шаг 1. Создаем таблицу значений и описываем колонки
ТЗ_Сотрудники = Новый ТаблицаЗначений;
ТЗ_Сотрудники.Колонки.Добавить("Сотрудник");
ТЗ_Сотрудники.Колонки.Добавить("ФилиалРаботы");
ТЗ_Сотрудники.Колонки.Добавить("ГодРождения", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4, 0)));

// Шаг 2. Выполняем обход справочника без сортировки
Выборка = Справочники.Сотрудники.Выбрать();
Пока Выборка.Следующий() Цикл
    
    // Исключаем группы, если справочник иерархический
    Если Выборка.ЭтоГруппа Тогда
        Продолжить;
    КонецЕсли;
    
    // Шаг 3. Заполняем строки таблицы значений
    НоваяСтрока = ТЗ_Сотрудники.Добавить();
    НоваяСтрока.Сотрудник     = Выборка.Ссылка;
    НоваяСтрока.ФилиалРаботы  = Выборка.ФилиалРаботы;
    
    // Извлекаем только год из даты рождения
    Если ЗначениеЗаполнено(Выборка.ДатаРождения) Тогда
        НоваяСтрока.ГодРождения = Год(Выборка.ДатаРождения);
    Иначе
        НоваяСтрока.ГодРождения = 0;
    КонецЕсли;
    
КонецЦикла;

// Шаг 4. Сортируем таблицу значений
// Сначала сортируем по представлению (наименованию) филиала, затем по году рождения
ТЗ_Сотрудники.Сортировать("ФилиалРаботы, ГодРождения Возр");

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

При заполнении параметров области макета важно обращаться к свойствам текущей строки обхода СтрокаТЗ, а не к самой таблице значений ТЗ_Сотрудники. Также применим метод ЗаполнитьЗначенияСвойств(), который автоматически сопоставит имена колонок таблицы значений с параметрами макета:


// Предположим, что ТабДок, Макет и ОбластьСтрока уже инициализированы
Для Каждого СтрокаТЗ Из ТЗ_Сотрудники Цикл
    
    // Очищаем параметры области перед заполнением
    ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаТЗ);
    
    // Если имена параметров макета отличаются, можно заполнить их вручную:
    // ОбластьСтрока.Параметры.Филиал       = СтрокаТЗ.ФилиалРаботы;
    // ОбластьСтрока.Параметры.Сотрудник     = СтрокаТЗ.Сотрудник;
    // ОбластьСтрока.Параметры.ГодРождения   = СтрокаТЗ.ГодРождения;
    
    ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;

---

Решение 2. Профессиональный подход с использованием Запросов

Использование таблицы значений для сортировки больших справочников крайне не рекомендуется в реальных бизнес-задачах. Это приводит к избыточному потреблению оперативной памяти сервера и увеличивает время работы программы. Профессиональным стандартом разработки на платформе «1С:Предприятие 8» является использование **Языка запросов**.

Запрос позволяет решить все проблемы одной технологической операцией: получить готовые отсортированные данные напрямую из базы данных. Мы задействуем встроенную функцию запроса ГОД() для моментального получения года из даты рождения, а также укажем явное упорядочивание по наименованию филиала.

Проанализируем пример кода с использованием запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Сотрудники.Ссылка КАК Сотрудник,
    |	Сотрудники.ФилиалРаботы КАК ФилиалРаботы,
    |	ГОД(Сотрудники.ДатаРождения) КАК ГодРождения
    |ИЗ
    |	Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |	НЕ Сотрудники.ЭтоГруппа
    |УПОРЯДОЧИТЬ ПО
    |	Сотрудники.ФилиалРаботы.Наименование ВОЗР,
    |	ГодРождения ВОЗР";

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

Пока Выборка.Следующий() Цикл
    
    // Заполняем параметры области макета напрямую из выборки запроса
    ОбластьСтрока.Параметры.Заполнить(Выборка);
    
    // Выводим готовую строку в табличный документ
    ТабДок.Вывести(ОбластьСтрока);
    
КонецЦикла;

В чем преимущества использования запроса?

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

← На главную