Почему «ЛЕВОЕ СОЕДИНЕНИЕ» в запросе 1С работает как «ВНУТРЕННЕЕ»?

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

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

В чем заключается проблема?

Основная причина скрывается в использовании секции ГДЕ. Когда вы делаете ЛЕВОЕ СОЕДИНЕНИЕ, для тех записей левой таблицы, для которых не нашлось пары в правой, все поля из правой таблицы заполняются значением NULL.

Если вы следом добавляете условие в секцию ГДЕ, например ГДЕ НЕ УведомлениеОбОтгрузкеМДЛП.ПометкаУдаления, система 1С работает следующим образом:

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

Таким образом, фильтр, наложенный в ГДЕ, фактически «убивает» левое соединение, превращая его во внутреннее. Мы теряем все строки, которые не имели соответствий в правой таблице.

Способ №1: Перенос условия в секцию «ПО»

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

Рассмотрим, как правильно изменить код запроса:


ВЫБРАТЬ
    ВР_РТУ.РТУ_Ссылка КАК РТУ,
    УведомлениеОбОтгрузкеМДЛП.Ссылка КАК УВ_Ссылка
ИЗ
    ВР_РТУ КАК ВР_РТУ
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.УведомлениеОбОтгрузкеМДЛП КАК УведомлениеОбОтгрузкеМДЛП
        ПО ВР_РТУ.РТУ_Ссылка = УведомлениеОбОтгрузкеМДЛП.Основание.Ссылка 
        И НЕ УведомлениеОбОтгрузкеМДЛП.ПометкаУдаления

Почему это работает: Условие, написанное в блоке ПО, становится частью правила связи. Если для конкретной записи РТУ не найдено Уведомление, или оно найдено, но помечено на удаление, условие не выполняется, и 1С корректно оставляет запись из левой таблицы, заполняя поля правой таблицы значением NULL.

Способ №2: Обработка NULL в секции «ГДЕ»

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

Для этого мы используем проверку на ЕСТЬ NULL:


ГДЕ
    (НЕ УведомлениеОбОтгрузкеМДЛП.ПометкаУдаления 
    ИЛИ УведомлениеОбОтгрузкеМДЛП.Ссылка ЕСТЬ NULL)

В этом примере мы используем логический оператор ИЛИ, который говорит: «Выведи мне записи, которые не помечены на удаление, либо те записи, для которых Уведомление вообще не было найдено».

Подведем итоги

Давайте резюмируем наши действия для избежания подобных ошибок в будущем:

Применяя эти правила, вы сможете писать надежные и предсказуемые запросы в 1С, которые всегда будут возвращать именно те данные, которые вы ожидаете!

← На главную