Как в отчете СКД вывести номенклатуру без установленной цены?

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

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

Анализируем причину проблемы

Разберем ситуацию, с которой столкнулся автор темы. В его запросе использовалось левое соединение справочника Номенклатура с виртуальной таблицей ЦеныНоменклатуры.СрезПоследних. Однако в секции ГДЕ было прописано условие ЦеныНоменклатурыСрезПоследних.Цена = 0. Это критическая ошибка по двум причинам:

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

Шаг 1: Правильное использование параметров виртуальных таблиц

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

Проанализируем, как должен выглядеть фрагмент кода для выбора цен:


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

Здесь &Период и фильтр по виду цены передаются «внутрь» механизма получения среза. Система сначала получит актуальные цены только для нужного вида, а затем аккуратно «приклеит» их к справочнику номенклатуры. Если цены нет — останется пустое место (NULL), но сама номенклатура не исчезнет.

Шаг 2: Обработка пустых значений с помощью ЕСТЬNULL

Чтобы в отчете вместо пустых ячеек (или для корректной фильтрации) выводился ноль, необходимо использовать функцию ЕСТЬNULL. Посмотрим на пример в секции ВЫБРАТЬ:


ВЫБРАТЬ
    СправочникНоменклатура.Ссылка КАК Номенклатура,
    ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
ИЗ
    Справочник.Номенклатура КАК СправочникНоменклатура

Функция ЕСТЬNULL(Поле, 0) проверяет значение: если там NULL, она возвращает 0, в противном случае — само значение поля. Это позволяет визуально отображать нулевую цену для товаров, которые не числятся в регистре.

Шаг 3: Настройка условий для вывода «Только без цен»

Если задача стоит вывести только те товары, у которых цена не задана, мы должны проверять именно наличие связи с регистром. Рассмотрим два способа реализации этого в коде запроса:

Способ А (проверка на NULL):


ГДЕ
    ЦеныНоменклатурыСрезПоследних.Цена ЕСТЬ NULL

Способ Б (использование ЕСТЬNULL в условии):


ГДЕ
    ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) = 0

Обратите внимание: если вы хотите видеть все товары (и с ценами, и без), секцию ГДЕ с фильтрами по цене нужно вообще исключить.

Итоговый исправленный запрос

С учетом всех правок и структуры запроса из конфигурации «Розница 2.3», итоговый код будет выглядеть следующим образом. Мы объединим получение остатков, штрихкодов и цен, сохраняя целостность списка номенклатуры.


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

Важные нюансы настройки СКД

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

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

← На главную