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