Как добавить исключение для одного сотрудника в запросе 1С?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет
← На главную

При разработке сложных отчетов или обработок в системе «1С:Предприятие 8.3» программисты часто сталкиваются с необходимостью наложить особые условия фильтрации на данные. Типичный пример: нужно выбрать данные по определенному способу отражения в учете для всех сотрудников, но для одного конкретного «особенного» сотрудника данные должны выбираться по другому способу. В этой статье мы подробно разберем, как правильно реализовать такую логику в запросе, избегая типичных ошибок производительности и обеспечивая корректность выборки.

Анализ проблемы: почему стандартный ВЫБОР в секции ГДЕ может не работать

Рассмотрим ситуацию, когда у нас есть запрос к регистрам учета зарплаты (например, РегистрНакопления.БухучетНачисленияУдержанияПоСотрудникам). Нам нужно получить данные, где поле СпособОтраженияЗарплатыВБухучете соответствует заданному параметру. Однако для сотрудника с определенным кодом нам нужно игнорировать этот параметр и искать данные по другому значению.

Часто начинающие разработчики пытаются использовать конструкцию ВЫБОР...КОГДА прямо в секции ГДЕ, как показано ниже:


ГДЕ
    ВЫБОР 
        КОГДА БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &Сотрудник ТОГДА
            БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете.Наименование ПОДОБНО "%Способ2%"
        ИНАЧЕ
            БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &Способ 
    КОНЕЦ

Проанализируем, почему этот подход неудачен:

  1. Производительность: Использование ВЫБОР внутри условий ГДЕ крайне негативно сказывается на скорости выполнения запроса. СУБД (например, MS SQL Server) в большинстве случаев не сможет использовать индексы таблиц для оптимизации поиска, что приведет к полному сканированию таблицы (Table Scan).
  2. Поиск по строке: Использование ПОДОБНО и обращение через точку к полю Наименование заставляет систему выполнять дополнительные соединения (JOIN) со справочником и медленный поиск по строке.
  3. Логическая сложность: Такие конструкции трудно отлаживать и расширять, если количество исключений вырастет.

Решение с использованием логических операторов И и ИЛИ

Правильный способ реализации исключений заключается в использовании классической булевой логики. Разберем, как перестроить условие, чтобы оно работало корректно и быстро. Нам нужно объединить два набора условий: «общие правила для всех» и «специальные правила для исключения».

Для этого воспользуемся оператором ИЛИ. Рассмотрим обновленный фрагмент кода:


ГДЕ
    (БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &Способ 
        И НЕ БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &СотрудникИсключение)
    ИЛИ 
    (БухучетНачисленияУдержанияПоСотрудникам.Сотрудник = &СотрудникИсключение 
        И БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособДляИсключения)

Разберем это условие по шагам:

  1. Первая часть (в скобках перед ИЛИ) выбирает всех сотрудников, кроме нашего «исключения», по стандартному способу отражения.
  2. Вторая часть выбирает только нашего сотрудника-исключение по его индивидуальному способу.
  3. Соединение этих частей через ИЛИ позволяет получить результирующую таблицу, в которой будут присутствовать оба набора данных.

Оптимизация запроса: использование параметров и списков

Чтобы сделать код более профессиональным и гибким, выясним причину, по которой жесткая привязка к коду сотрудника («ПА2») является плохой практикой. Если завтра появится еще один сотрудник с особыми условиями, вам придется снова менять текст запроса.

Вместо этого рекомендуется использовать массивы или списки значений. Посмотрим на пример реализации с параметрами:


// В модуле перед выполнением запроса
СписокИсключений = Новый Массив;
СписокИсключений.Добавить(Справочники.Сотрудники.НайтиПоКоду("ПА2"));

Запрос.УстановитьПараметр("СписокИсключений", СписокИсключений);
Запрос.УстановитьПараметр("СпособОсновной", Объект.Проект);
Запрос.УстановитьПараметр("СпособОсобый", Объект.ПроектДляАУП);

// В тексте запроса
ГДЕ 
    (БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособОсновной 
     И НЕ БухучетНачисленияУдержанияПоСотрудникам.Sotrudnik В (&СписокИсключений))
    ИЛИ 
    (БухучетНачисленияУдержанияПоСотрудникам.Сотрудник В (&СписокИсключений) 
     И БухучетНачисленияУдержанияПоСотрудникам.СпособОтраженияЗарплатыВБухучете = &СпособОсобый)

Использование оператора В (&Параметр) делает ваш запрос универсальным: он будет работать корректно как для одного сотрудника, так и для целой группы, если вы решите расширить список исключений.

Проверка данных в регистрах: почему запрос может «не видеть» сотрудника

Проанализируем ситуацию, описанную в обсуждении: иногда даже при правильном запросе данные не попадают в выборку. Выясним причину этого явления. В конфигурациях вроде «1С:Зарплата и управление персоналом 3.1» данные в регистре БухучетНачисленияУдержанияПоСотрудникам формируются в момент проведения расчетных документов.

Важный момент: Если в настройках сотрудника или подразделения способ отражения был изменен после того, как документ начисления был рассчитан и проведен, данные в регистре останутся старыми. Запрос обращается именно к физической таблице регистра, а не к текущим настройкам в карточке сотрудника.

Для исправления этой ситуации необходимо:

Использование временных таблиц для сложной логики исключений

Если логика определения «кто является исключением» становится слишком сложной (например, зависит от должности, вида договора или подразделения), мы рекомендуем использовать временные таблицы (ВТ). Это сделает ваш запрос чище и позволит избежать ошибок при соединении таблиц.

Рассмотрим алгоритм работы через ВТ:

  1. Создаем временную таблицу ВТ_ЦелевыеСотрудники, в которой заранее подготавливаем список нужных сотрудников и сопоставленных им способов отражения.
  2. Соединяем основную таблицу регистра с этой ВТ через ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полям Сотрудник и СпособОтражения.

Пример структуры такого запроса:


// Шаг 1: Формируем список сотрудников и их индивидуальных настроек
ВЫБРАТЬ
    Сотрудник,
    &СпособОсновной КАК СпособДляПоиска
ПОМЕСТИТЬ ВТ_Настройки
ИЗ Справочник.Сотрудники ГДЕ Ссылка НЕ В (&СписокИсключений)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Ссылка,
    &СпособОсобый
ИЗ Справочник.Сотрудники ГДЕ Ссылка В (&СписокИсключений)
;
////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Основная выборка
ВЫБРАТЬ
    БухДанные.Сотрудник,
    БухДанные.Сумма
ИЗ
    РегистрНакопления.БухучетНачисленияУдержанияПоСотрудникам КАК БухДанные
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Настройки КАК Настройки
    ПО БухДанные.Сотрудник = Настройки.Сотрудник
    И БухДанные.СпособОтраженияЗарплатыВБухучете = Настройки.СпособДляПоиска

Этот метод является наиболее производительным и масштабируемым в профессиональной разработке на платформе 1С. Мы четко разделяем бизнес-логику (кто и как должен учитываться) и техническую выборку данных из тяжелых таблиц регистров.

Подводя итог, помните: при работе с исключениями в запросах всегда отдавайте приоритет простым логическим условиям И/ИЛИ или предварительной подготовке данных во временных таблицах. Это гарантирует быструю работу системы и отсутствие ошибок при росте объема базы данных.

← На главную