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