Как вывести все строки в отчете 1С при левом соединении, даже если нет данных во второй таблице?

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

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

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

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

Однако, если мы добавим условие ГДЕ Цены.ВидЦены = &ВидЦены, система отфильтрует итоговый результат. Поскольку для отсутствующих цен поле ВидЦены равно NULL, оно не пройдет проверку на равенство конкретному значению. В итоге ЛЕВОЕ СОЕДИНЕНИЕ фактически превращается во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, и строки с незаполненными ценами пропадают.

Решение 1: Параметры виртуальной таблицы (рекомендуемый способ)

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

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


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

Обратим внимание на функцию ЕСТЬNULL. Мы используем её для того, чтобы вместо пустого значения в колонке «Цена» выводился ноль. Это критически важно для дальнейших математических операций в отчете, так как любое умножение на NULL даст в итоге пустую ячейку.

Решение 2: Перенос условия в секцию связи (ПО)

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

Проанализируем пример такого соединения:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
ПО ВыпускПродукцииОбороты.АналитикаУчетаНоменклатуры.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
    И ВыпускПродукцииОбороты.АналитикаУчетаНоменклатуры.Характеристика = ЦеныНоменклатурыСрезПоследних.Характеристика
    И ЦеныНоменклатурыСрезПоследних.ВидЦены = &Дилер

В данном случае условие ЦеныНоменклатурыСрезПоследних.ВидЦены = &Дилер является частью правила соединения, а не фильтром всей выборки. Это сохраняет целостность левой таблицы.

Нюансы работы с характеристиками и NULL

Выясним причину, по которой иногда данные все равно могут не сходиться. В 1С существует разница между «Пустой ссылкой» и значением NULL. Пустая ссылка — это реальное значение типа «СправочникСсылка», которое может быть записано в регистр. NULL — это отсутствие данных в принципе.

Если в регистре «Выпуск продукции» характеристика не указана (стоит пустая ссылка), а в регистре цен записи для этой номенклатуры с пустой характеристикой нет вообще, то при соединении возникнет сравнение ПустаяСсылка = NULL, что даст ложь. Чтобы избежать потери строк в таких случаях, рекомендуется использовать ЕСТЬNULL в условиях связи или предварительно обрабатывать данные во временных таблицах.

Использование временных таблиц для стабильности отчета

Для больших отчетов (более 10-20 тысяч строк) мы рекомендуем использовать временные таблицы. Это делает запрос прозрачным и помогает избежать ошибок при сложных соединениях. Разберем этот подход по шагам:

  1. Выбираем все данные из основного регистра (Выпуск продукции) во временную таблицу ВТ_Выпуск.
  2. Индексируем временную таблицу по полям Номенклатура и Характеристика.
  3. Выбираем цены в другую временную таблицу ВТ_Цены с уже установленным фильтром по виду цен.
  4. В финальном запросе соединяем ВТ_Выпуск (левая) и ВТ_Цены (правая).

Такой подход гарантирует, что никакие «кривые» записи в регистре сведений не повлияют на итоговое количество строк выпускаемой продукции.

Особенности Системы компоновки данных (СКД)

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

РегистрСведений.ЦеныНоменклатуры.СрезПоследних({&Период}, {ВидЦены = &ВидЦены})

Это позволит пользователю гибко менять настройки отбора в пользовательском режиме, а системе — формировать оптимальный SQL-запрос. Также на вкладке «Наборы данных» можно настроить Роли полей. Если указать, что поле номенклатуры является обязательным и относится к основному набору данных, СКД будет более корректно обрабатывать левые соединения при компоновке финального результата.

Важный момент: Если после всех исправлений количество строк в отчете все равно меньше ожидаемого, проверьте наличие дублей в регистре сведений. Если на один и тот же момент времени по одной номенклатуре и характеристике в базе окажется две разные цены, левое соединение может не только уменьшить, но и «раздуть» количество строк в отчете (сделать их больше, чем в выпуске). В таких случаях используйте группировку или выбирайте МАКСИМУМ(Цена).

← На главную