При разработке отчетов и обработок в системе «1С:Предприятие 8» программисты часто сталкиваются с задачей выборки данных из справочников с их последующей сортировкой. Однако стандартный метод Выбрать() менеджера справочника имеет жесткие платформенные ограничения. Например, попытка отсортировать сотрудников по ссылочному реквизиту (такому как филиал) или по части даты (только по году рождения) напрямую через этот метод приведет к ошибке выполнения.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем внутренние механизмы работы платформы 1С и рассмотрим два практических способа решения задачи: простой учебный метод с использованием Таблицы Значений и профессиональный оптимальный метод с использованием Языка запросов 1С.
Попытка вызвать метод выборки в коде следующим образом:
Выборка = Справочники.Сотрудники.Выбрать(,,,"ФилиалРаботы");
Вызовет системную ошибку: «Выборка может быть упорядочена только по реквизитам, имеющим базовый тип и для которых установлен признак индексирования». Давайте разберем, почему это происходит:
Выбрать() умеет выполнять сортировку силами СУБД только по полям простых (базовых) типов. К ним относятся Строка, Число, Дата и Булево. Реквизит ФилиалРаботы имеет тип ссылки (например, СправочникСсылка.Филиалы), который не является базовым.---
Если вы только начинаете изучать программирование в 1С и еще не освоили язык запросов, решить задачу можно с помощью выгрузки данных во временную таблицу значений (ТЗ) с её последующей сортировкой. Этот способ отлично подходит для понимания объектной модели платформы.
Рассмотрим пошагово, как реализовать этот алгоритм:
Выбрать() без параметров сортировки.Год().Посмотрим на практический пример реализации этого алгоритма в коде:
// Шаг 1. Создаем таблицу значений и описываем колонки
ТЗ_Сотрудники = Новый ТаблицаЗначений;
ТЗ_Сотрудники.Колонки.Добавить("Сотрудник");
ТЗ_Сотрудники.Колонки.Добавить("ФилиалРаботы");
ТЗ_Сотрудники.Колонки.Добавить("ГодРождения", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4, 0)));
// Шаг 2. Выполняем обход справочника без сортировки
Выборка = Справочники.Сотрудники.Выбрать();
Пока Выборка.Следующий() Цикл
// Исключаем группы, если справочник иерархический
Если Выборка.ЭтоГруппа Тогда
Продолжить;
КонецЕсли;
// Шаг 3. Заполняем строки таблицы значений
НоваяСтрока = ТЗ_Сотрудники.Добавить();
НоваяСтрока.Сотрудник = Выборка.Ссылка;
НоваяСтрока.ФилиалРаботы = Выборка.ФилиалРаботы;
// Извлекаем только год из даты рождения
Если ЗначениеЗаполнено(Выборка.ДатаРождения) Тогда
НоваяСтрока.ГодРождения = Год(Выборка.ДатаРождения);
Иначе
НоваяСтрока.ГодРождения = 0;
КонецЕсли;
КонецЦикла;
// Шаг 4. Сортируем таблицу значений
// Сначала сортируем по представлению (наименованию) филиала, затем по году рождения
ТЗ_Сотрудники.Сортировать("ФилиалРаботы, ГодРождения Возр");
После того как таблица значений успешно отсортирована, нам необходимо вывести её в макет табличного документа. Разберем, как правильно организовать цикл вывода, чтобы избежать типичной ошибки начинающих разработчиков — дублирования первой строки.
При заполнении параметров области макета важно обращаться к свойствам текущей строки обхода СтрокаТЗ, а не к самой таблице значений ТЗ_Сотрудники. Также применим метод ЗаполнитьЗначенияСвойств(), который автоматически сопоставит имена колонок таблицы значений с параметрами макета:
// Предположим, что ТабДок, Макет и ОбластьСтрока уже инициализированы
Для Каждого СтрокаТЗ Из ТЗ_Сотрудники Цикл
// Очищаем параметры области перед заполнением
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаТЗ);
// Если имена параметров макета отличаются, можно заполнить их вручную:
// ОбластьСтрока.Параметры.Филиал = СтрокаТЗ.ФилиалРаботы;
// ОбластьСтрока.Параметры.Сотрудник = СтрокаТЗ.Сотрудник;
// ОбластьСтрока.Параметры.ГодРождения = СтрокаТЗ.ГодРождения;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
---
Использование таблицы значений для сортировки больших справочников крайне не рекомендуется в реальных бизнес-задачах. Это приводит к избыточному потреблению оперативной памяти сервера и увеличивает время работы программы. Профессиональным стандартом разработки на платформе «1С:Предприятие 8» является использование **Языка запросов**.
Запрос позволяет решить все проблемы одной технологической операцией: получить готовые отсортированные данные напрямую из базы данных. Мы задействуем встроенную функцию запроса ГОД() для моментального получения года из даты рождения, а также укажем явное упорядочивание по наименованию филиала.
Проанализируем пример кода с использованием запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Сотрудники.Ссылка КАК Сотрудник,
| Сотрудники.ФилиалРаботы КАК ФилиалРаботы,
| ГОД(Сотрудники.ДатаРождения) КАК ГодРождения
|ИЗ
| Справочник.Сотрудники КАК Сотрудники
|ГДЕ
| НЕ Сотрудники.ЭтоГруппа
|УПОРЯДОЧИТЬ ПО
| Сотрудники.ФилиалРаботы.Наименование ВОЗР,
| ГодРождения ВОЗР";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Заполняем параметры области макета напрямую из выборки запроса
ОбластьСтрока.Параметры.Заполнить(Выборка);
// Выводим готовую строку в табличный документ
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
ВЫБРАТЬ, а не все реквизиты справочника целиком.Сотрудники.ФилиалРаботы.Наименование позволяет без труда отсортировать сотрудников по алфавитному названию филиала, в то время как обычная выборка пыталась бы сортировать их по внутренним ссылкам-идентификаторам.Таким образом, для простых учебных задач или работы с очень маленькими объемами данных вы можете использовать выгрузку в Таблицу Значений с последующим методом Сортировать(). Для решения реальных задач автоматизации всегда отдавайте предпочтение механизму запросов.