Почему левое соединение в запросе 1С работает как внутреннее и пропадают записи без свойств?

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

При работе с механизмами дополнительных свойств и категорий в конфигурациях на платформе 1С:Предприятие (например, в «Управление торговлей 10.3», «Управление производственным предприятием» или современных ERP-системах) разработчики часто сталкиваются с необходимостью вывести свойства объектов в одном отчете с основными данными. Для этого традиционно используется левое соединение. Однако нередко возникает ситуация, когда после написания запроса документы или справочники, у которых нужное свойство не заполнено, просто исчезают из результирующей таблицы. Получается, что левое соединение начинает отрабатывать как внутреннее.

В этой статье мы подробно разберем, почему возникает эта классическая ошибка, детально проанализируем поведение СУБД при выполнении подобных запросов, а также рассмотрим несколько способов решения этой проблемы: от простого исправления условий связи до глубокой оптимизации запроса и использования встроенных механизмов СКД.

Представим типовую задачу. В конфигурации «Управление торговлей 10.3» для документов реализации добавлено новое свойство «Водитель». Оно заполняется не для каждого документа. Нам требуется получить таблицу всех оборотов продаж с указанием водителя, если он задан. Если водитель не указан, документ все равно должен остаться в списке, а в поле водителя должно отобразиться пустое значение.

Выясняем причину: почему «ГДЕ» ломает левое соединение

Проанализируем исходный запрос, который приводит к ошибке:


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

Давайте разберем по шагам, как этот запрос обрабатывается СУБД:

  1. Этап соединения таблиц (ПО): Система берет таблицу оборотов продаж и пытается сопоставить каждую строку с таблицей регистра сведений ЗначенияСвойствОбъектов по условию равенства ссылки документа и измерения Объект. На этом шаге все работает верно. Для документов, у которых в регистре нет записи со свойством, создается строка, где все поля правой таблицы (включая Свойство и Значение) принимают значение NULL.
  2. Этап фильтрации (ГДЕ): После того как таблицы были соединены, СУБД переходит к обработке секции ГДЕ. Здесь написано жесткое условие: ЗначенияСвойствОбъектов.Свойство = &СвойствоВодитель. Система начинает проверять каждую строчку результирующего набора данных. Если у документа не было задано ни одного свойства, то в поле Свойство находится значение NULL. СУБД вычисляет выражение NULL = &СвойствоВодитель. По правилам булевой логики баз данных, любое сравнение с NULL дает результат «Ложь» (или Unknown). В итоге все строки, где свойство не было заполнено, безжалостно отсекаются фильтром.

Таким образом, наложение фильтра на правую (присоединяемую) таблицу в секции ГДЕ фактически превращает левое соединение во внутреннее (INNER JOIN). Это одна из самых распространенных логических ошибок начинающих разработчиков 1С.

Решение №1: Перенос условия в секцию связи «ПО»

Самый простой и быстрый способ исправить эту ошибку — перенести условие фильтрации правой таблицы непосредственно в условия соединения (секция ПО). Давайте посмотрим на правильный вариант запроса:


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

В этом случае СУБД сначала отфильтрует записи в таблице ЗначенияСвойствОбъектов, выбрав только те, которые относятся к свойству «Водитель», а уже затем выполнит левое соединение с продажами. Те документы, у которых данное свойство не заполнено, гарантированно останутся в выборке, а в поле Водитель для них вернется чистое значение NULL.

Решение №2: Оптимизация через временные таблицы (Рекомендуется)

Хотя решение с переносом условия в секцию ПО является абсолютно рабочим, оно может работать неоптимально на крупных информационных базах. Регистр сведений ЗначенияСвойствОбъектов в реальных базах «Управление торговлей 10.3» часто разрастается до миллионов записей, так как хранит свойства для самых разных объектов: номенклатуры, контрагентов, документов, договоров.

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


// Шаг 1: Выбираем только свойства нужного типа во временную таблицу
ВЫБРАТЬ
    ЗначенияСвойствОбъектов.Объект КАК Объект,
    ЗначенияСвойствОбъектов.Значение КАК Водитель
ПОМЕСТИТЬ ВТ_ВодителиПоДокументам
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
    ЗначенияСвойствОбъектов.Свойство = &СвойствоВодитель

ИНДЕКСИРОВАТЬ ПО
    Объект
;

// Шаг 2: Соединяем продажи со значительно уменьшенной временной таблицей
ВЫБРАТЬ
    ПродажиОбороты.СтоимостьОборот,
    ЕСТЬNULL(ВТ_ВодителиПоДокументам.Водитель, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК Водитель,
    ПродажиОбороты.ДокументПродажи
ИЗ
    РегистрНакопления.Продажи.Обороты(&Дата1, &Дата2, Авто, ) КАК ПродажиОбороты
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ВодителиПоДокументам КАК ВТ_ВодителиПоДокументам
    ПО ПродажиОбороты.ДокументПродажи = ВТ_ВодителиПоДокументам.Объект

Давайте проанализируем преимущества этого подхода:

  1. Сужение объема данных: На первом шаге мы создаем очень легкую временную таблицу ВТ_ВодителиПоДокументам, которая содержит только те записи, у которых свойство равно «Водитель». Мы отсекаем весь гигантский объем лишних свойств других объектов.
  2. Индексация: Конструкция ИНДЕКСИРОВАТЬ ПО Объект создает временный индекс. При последующем левом соединении СУБД мгновенно найдет соответствия по индексу, что обеспечит максимальную скорость работы даже на базах объемом в терабайты.
  3. Использование функции ЕСТЬNULL: Мы применили функцию ЕСТЬNULL. Если у документа нет водителя, вместо невыразительного значения NULL в результат попадет стандартная пустая ссылка справочника значений свойств, что исключит проблемы с отображением пустых полей в отчетах или формах.

Решение №3: Механизм характеристик в СКД (Без написания соединений)

Если ваша задача — построить отчет с помощью Системы компоновки данных (СКД), то вам вообще не обязательно вручную прописывать левые соединения с регистром сведений. В платформе 1С реализован мощный механизм под названием Характеристики.

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

  1. В схеме компоновки данных выберите набор данных (запрос), который выбирает продажи (без всяких соединений со свойствами).
  2. Перейдите на вкладку Характеристики в конструкторе схемы компоновки.
  3. Добавьте новую строку характеристик и укажите следующие параметры:
    • Путь к данным: ДокументПродажи (или другой объект, свойства которого нужно получить).
    • Источник видов характеристик: Таблица или План видов характеристик (например, ПВХ СвойстваОбъектов).
    • Источник значений характеристик: Регистр сведений ЗначенияСвойствОбъектов.
    • Связь видов: Поле, связывающее объект со свойством.

После такой настройки в списке доступных полей СКД у поля ДокументПродажи появится виртуальный плюс, раскрыв который, вы увидите все дополнительные свойства (включая «Водитель») так, будто они являются реальными реквизитами самого документа. Вы можете просто перетащить поле ДокументПродажи.[Водитель] в выбранные поля отчета. Платформа СКД самостоятельно сформирует оптимальный SQL-запрос с правильным левым соединением и корректной обработкой пустых значений.

Важные нюансы работы со свойствами объектов

При работе с регистром ЗначенияСвойствОбъектов полезно помнить еще о нескольких важных моментах:

Используйте описанные методики, избегайте фильтрации по присоединяемым таблицам в секции ГДЕ, и ваши запросы в 1С всегда будут работать быстро и корректно!

← На главную