Почему «Левое соединение» в 1С не возвращает NULL и как это исправить?

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

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

Выявляем причину проблемы: влияние секции ГДЕ

Главная ошибка, с которой сталкиваются при написании запросов, заключается в неверном использовании секции ГДЕ (WHERE). Когда мы накладываем условия фильтрации на поля правой таблицы в секции ГДЕ, мы фактически принуждаем систему отсекать все записи, где связь не была установлена.

Рассмотрим логику работы системы: при выполнении ЛЕВОГО СОЕДИНЕНИЯ, если запись в правой таблице не найдена, все её поля принимают значение NULL. Если затем в секции ГДЕ мы указываем условие, например, ТаблицаПравая.Партнер = &Партнер, система проверяет: равно ли NULL значение нашего параметра? Конечно, нет. В результате строка, которая должна была остаться в отчете с пустыми полями справа, просто удаляется из результата запроса.

Таким образом, использование условий на поля правой таблицы в секции ГДЕ делает ЛЕВОЕ СОЕДИНЕНИЕ фактически ВНУТРЕННИМ СОЕДИНЕНИЕМ (INNER JOIN), что и приводит к потере данных.

Способ 1: Перенос условий в секцию ПО

Наиболее простым и эффективным способом решения проблемы является перенос условий фильтрации непосредственно в секцию ПО (ON) соединения. Когда мы задаем условия именно в момент связки таблиц, система учитывает их при формировании выборки, не отсекая записи с NULL.

Давайте посмотрим, как изменить запрос, чтобы фильтрация работала корректно:


ВЫБРАТЬ
    ЛеваяТаблица.Номенклатура,
    ПраваяТаблица.Количество
ИЗ
    РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК ЛеваяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ
    РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК ПраваяТаблица
ПО
    ЛеваяТаблица.Номенклатура = ПраваяТаблица.Номенклатура
    И ПраваяТаблица.Партнер = &Партнер

В этом примере условие ПраваяТаблица.Партнер = &Партнер находится внутри секции ПО. Теперь, если для номенклатуры из левой таблицы не найдется записи с указанным партнером в правой, запрос все равно выведет эту номенклатуру, но поля из правой таблицы будут заполнены значениями NULL.

Способ 2: Использование вложенных запросов

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

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


ВЫБРАТЬ
    ЛеваяТаблица.Номенклатура,
    ОтфильтрованнаяПравая.Количество
ИЗ
    РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК ЛеваяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ
    (ВЫБРАТЬ
        Таблица.Номенклатура КАК Номенклатура,
        Таблица.Количество КАК Количество
    ИЗ
        РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК Таблица
    ГДЕ
        Таблица.Партнер = &Партнер) КАК ОтфильтрованнаяПравая
ПО
    ЛеваяТаблица.Номенклатура = ОтфильтрованнаяПравая.Номенклатура

При таком подходе фильтрация происходит еще до того, как таблицы «встретятся» друг с другом. Это дает четкое понимание того, какие именно данные мы пытаемся присоединить.

Советы по отладке сложных запросов

Если вы все еще не получаете ожидаемого результата, воспользуйтесь проверенной методикой отладки:

  1. Разделите запрос на части: Не пытайтесь писать сложный запрос целиком. Выполните отдельно запрос к левой таблице и убедитесь, что она возвращает ожидаемый набор записей.
  2. Проверьте правую таблицу: Отдельно выполните запрос к правой таблице с фильтрами. Убедитесь, что там действительно есть данные, которые должны были «подтянуться».
  3. Используйте консоль запросов: Наблюдая за результатами двух независимых наборов данных, вы гораздо быстрее заметите, почему связи не происходит (например, из-за различий в аналитике, датах или неверных условиях).
  4. Проверьте параметры виртуальных таблиц: Помните, что виртуальные таблицы, такие как Обороты, учитывают параметры периода. Если в параметрах указан узкий диапазон, данные могут отсутствовать в принципе, и никакое соединение не поможет их «найти».

Работая последовательно и перенося фильтры из ГДЕ в секцию ПО, вы всегда сможете добиться корректного отображения NULL и построить отчет так, как задумано.

← На главную