При разработке сложных отчетов или обработок в системе «1С:Предприятие 8.3» программисты часто сталкиваются с необходимостью наложить особые условия фильтрации на данные. Типичный пример: нужно выбрать данные по определенному способу отражения в учете для всех сотрудников, но для одного конкретного «особенного» сотрудника данные должны выбираться по другому способу. В этой статье мы подробно разберем, как правильно реализовать такую логику в запросе, избегая типичных ошибок производительности и обеспечивая корректность выборки.
Рассмотрим ситуацию, когда у нас есть запрос к регистрам учета зарплаты (например, РегистрНакопления.БухучетНачисленияУдержанияПоСотрудникам). Нам нужно получить данные, где поле СпособОтраженияЗарплатыВБухучете соответствует заданному параметру. Однако для сотрудника с определенным кодом нам нужно игнорировать этот параметр и искать данные по другому значению.
Часто начинающие разработчики пытаются использовать конструкцию ВЫБОР...КОГДА прямо в секции ГДЕ, как показано ниже:
ГДЕ
ВЫБОР
КОГДА БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &Сотрудник ТОГДА
БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете.Наименование ПОДОБНО "%Способ2%"
ИНАЧЕ
БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &Способ
КОНЕЦ
Проанализируем, почему этот подход неудачен:
ВЫБОР внутри условий ГДЕ крайне негативно сказывается на скорости выполнения запроса. СУБД (например, MS SQL Server) в большинстве случаев не сможет использовать индексы таблиц для оптимизации поиска, что приведет к полному сканированию таблицы (Table Scan).ПОДОБНО и обращение через точку к полю Наименование заставляет систему выполнять дополнительные соединения (JOIN) со справочником и медленный поиск по строке.Правильный способ реализации исключений заключается в использовании классической булевой логики. Разберем, как перестроить условие, чтобы оно работало корректно и быстро. Нам нужно объединить два набора условий: «общие правила для всех» и «специальные правила для исключения».
Для этого воспользуемся оператором ИЛИ. Рассмотрим обновленный фрагмент кода:
ГДЕ
(БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &Способ
И НЕ БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &СотрудникИсключение)
ИЛИ
(БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &СотрудникИсключение
И БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособДляИсключения)
Разберем это условие по шагам:
ИЛИ) выбирает всех сотрудников, кроме нашего «исключения», по стандартному способу отражения.ИЛИ позволяет получить результирующую таблицу, в которой будут присутствовать оба набора данных.Чтобы сделать код более профессиональным и гибким, выясним причину, по которой жесткая привязка к коду сотрудника («ПА2») является плохой практикой. Если завтра появится еще один сотрудник с особыми условиями, вам придется снова менять текст запроса.
Вместо этого рекомендуется использовать массивы или списки значений. Посмотрим на пример реализации с параметрами:
// В модуле перед выполнением запроса
СписокИсключений = Новый Массив;
СписокИсключений.Добавить(Справочники.Сотрудники.НайтиПоКоду("ПА2"));
Запрос.УстановитьПараметр("СписокИсключений", СписокИсключений);
Запрос.УстановитьПараметр("СпособОсновной", Объект.Проект);
Запрос.УстановитьПараметр("СпособОсобый", Объект.ПроектДляАУП);
// В тексте запроса
ГДЕ
(БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособОсновной
И НЕ БухучетНачисленияУдержанияПоСотрудникам.Sotrudnik В (&СписокИсключений))
ИЛИ
(БухучетНачисленияУдержанияПоСотрудникам.Сотрудник В (&СписокИсключений)
И БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособОсобый)
Использование оператора В (&Параметр) делает ваш запрос универсальным: он будет работать корректно как для одного сотрудника, так и для целой группы, если вы решите расширить список исключений.
Проанализируем ситуацию, описанную в обсуждении: иногда даже при правильном запросе данные не попадают в выборку. Выясним причину этого явления. В конфигурациях вроде «1С:Зарплата и управление персоналом 3.1» данные в регистре БухучетНачисленияУдержанияПоСотрудникам формируются в момент проведения расчетных документов.
Важный момент: Если в настройках сотрудника или подразделения способ отражения был изменен после того, как документ начисления был рассчитан и проведен, данные в регистре останутся старыми. Запрос обращается именно к физической таблице регистра, а не к текущим настройкам в карточке сотрудника.
Для исправления этой ситуации необходимо:
Если логика определения «кто является исключением» становится слишком сложной (например, зависит от должности, вида договора или подразделения), мы рекомендуем использовать временные таблицы (ВТ). Это сделает ваш запрос чище и позволит избежать ошибок при соединении таблиц.
Рассмотрим алгоритм работы через ВТ:
ВТ_ЦелевыеСотрудники, в которой заранее подготавливаем список нужных сотрудников и сопоставленных им способов отражения.ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полям Сотрудник и СпособОтражения.Пример структуры такого запроса:
// Шаг 1: Формируем список сотрудников и их индивидуальных настроек
ВЫБРАТЬ
Сотрудник,
&СпособОсновной КАК СпособДляПоиска
ПОМЕСТИТЬ ВТ_Настройки
ИЗ Справочник.Сотрудники ГДЕ Ссылка НЕ В (&СписокИсключений)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Ссылка,
&СпособОсобый
ИЗ Справочник.Сотрудники ГДЕ Ссылка В (&СписокИсключений)
;
////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Основная выборка
ВЫБРАТЬ
БухДанные.Сотрудник,
БухДанные.Сумма
ИЗ
РегистрНакопления.БухучетНачисленияУдержанияПоСотрудникам КАК БухДанные
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Настройки КАК Настройки
ПО БухДанные.Сотрудник = Настройки.Сотрудник
И БухДанные.СпособОтраженияЗарплатыВБухучете = Настройки.СпособДляПоиска
Этот метод является наиболее производительным и масштабируемым в профессиональной разработке на платформе 1С. Мы четко разделяем бизнес-логику (кто и как должен учитываться) и техническую выборку данных из тяжелых таблиц регистров.
Подводя итог, помните: при работе с исключениями в запросах всегда отдавайте приоритет простым логическим условиям И/ИЛИ или предварительной подготовке данных во временных таблицах. Это гарантирует быструю работу системы и отсутствие ошибок при росте объема базы данных.