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