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