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