Почему запрос в 1С возвращает пустой результат при фильтрации сотрудников?

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

При разработке отчетов или обработок на платформе 1С:Предприятие часто возникает необходимость отобрать список сотрудников, исключив из него уволенных. Однако при использовании конструкций ЛЕВОЕ СОЕДИНЕНИЕ и последующей фильтрации по полю состояния многие разработчики сталкиваются с тем, что результат запроса оказывается пустым. Давайте разберем, почему это происходит и как исправить эту логическую ошибку.

Выясняем причину возникновения ошибки

Основная проблема кроется в особенностях работы с неопределенными значениями в SQL-подобных языках, на которых базируется язык запросов 1С. Когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ основной таблицы с регистром состояний, для тех сотрудников, по которым в регистре нет записей (например, они еще не уволены или по ним не зафиксировано состояние), платформа подставляет значение NULL.

В языке запросов 1С сравнение любого значения (в том числе NULL) с помощью оператора = или <> всегда возвращает ЛОЖЬ. Поэтому, когда вы пишете условие ГДЕ Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Увольнение), записи, в которых Состояние равно NULL, просто отсекаются из итоговой выборки. В итоге вы теряете всех сотрудников, чье состояние не было заполнено.

Рассмотрим способы решения проблемы

Чтобы корректно отобрать сотрудников, нам нужно учитывать состояние NULL как допустимое. Рассмотрим два основных подхода.

Способ 1: Использование конструкции ЕСТЬ NULL

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

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


ГДЕ (т100.Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Увольнение)
    ИЛИ т100.Состояние ЕСТЬ NULL)

Такой подход позволяет сохранить в выборке всех работающих сотрудников. Использование ЕСТЬ NULL — это стандартный и наиболее эффективный способ проверки наличия данных в полях, которые могли остаться незаполненными в результате левого соединения.

Оптимизируем структуру запроса

Часто для решения задачи с определением работающих сотрудников не требуется создание нескольких промежуточных временных таблиц. Если нам нужно просто вывести информацию о месте выплаты зарплаты и при этом отсечь уволенных, мы можем значительно сократить код, используя прямое соединение с регистром сведений ДанныеСостоянийСотрудников.

Рассмотрим пример оптимизированного запроса:


ВЫБРАТЬ
    МестаВыплаты.Сотрудник КАК Сотрудник,
    МестаВыплаты.ФизическоеЛицо КАК ФизическоеЛицо,
    МестаВыплаты.Вид КАК Вид,
    МестаВыплаты.МестоВыплаты КАК МестоВыплаты,
    ДанныеСостояний.Состояние КАК Состояние
ИЗ
    РегистрСведений.МестаВыплатыЗарплатыСотрудников КАК МестаВыплаты
ЛЕВОЕ СОЕДИНЕНИЕ
    РегистрСведений.ДанныеСостоянийСотрудников КАК ДанныеСостояний
ПО
    МестаВыплаты.Сотрудник = ДанныеСостояний.Сотрудник
ГДЕ
    (ДанныеСостояний.Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияСотрудника.Увольнение)
    ИЛИ ДанныеСостояний.Состояние ЕСТЬ NULL)

Рекомендации по работе с данными

  1. Проверяйте результат до фильтрации: Если запрос не возвращает данные, попробуйте временно убрать блок ГДЕ. Это позволит увидеть, какие именно значения (NULL или конкретные элементы перечислений) приходят в результат запроса.
  2. Используйте виртуальные таблицы: В задачах, связанных с регистрами сведений, старайтесь использовать виртуальную таблицу СрезПоследних. Она позволяет получить актуальное состояние на нужную дату без ручной группировки по периодам.
  3. Внимательно относитесь к соединениям: Помните, что накладывая условия в блоке ГДЕ на поля присоединенной таблицы, вы фактически превращаете ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ. Если вам важно сохранить все строки из основной таблицы, накладывайте условия на состояние непосредственно в блоке ПО.

Надеемся, что этот разбор поможет вам избежать подобных ошибок в будущем и писать более чистый и производительный код на языке запросов 1С!

← На главную