При разработке отчетов на базе Системы компоновки данных (СКД) часто возникает задача вывести полный список товаров, даже если по ним отсутствуют данные в регистрах (например, не установлены цены или нет остатков). Типичная ошибка заключается в том, что при использовании ЛЕВОЕ СОЕДИНЕНИЕ записи без цен «исчезают» из итогового результата. Рассмотрим подробно, почему это происходит и как правильно составить запрос, чтобы отчет выводил всю номенклатуру.
Разберем ситуацию, с которой столкнулся автор темы. В его запросе использовалось левое соединение справочника Номенклатура с виртуальной таблицей ЦеныНоменклатуры.СрезПоследних. Однако в секции ГДЕ было прописано условие ЦеныНоменклатурыСрезПоследних.Цена = 0. Это критическая ошибка по двум причинам:
NULL. Условие Цена = 0 проверяет наличие числа ноль, но NULL не равен нулю. В результате все товары без цен отсекаются.ГДЕ, наложенное на поля «правой» (присоединяемой) таблицы, фактически превращает ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ. Если данных в правой таблице нет, условие не может быть вычислено как истинное, и вся строка удаляется из результата.Для виртуальных таблиц (таких как СрезПоследних) в 1С крайне важно передавать условия (период, вид цены) непосредственно в параметры самой таблицы, а не в условия соединения ПО или секцию ГДЕ. Это не только ускоряет запрос, но и гарантирует корректную работу левого соединения.
Проанализируем, как должен выглядеть фрагмент кода для выбора цен:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
Здесь &Период и фильтр по виду цены передаются «внутрь» механизма получения среза. Система сначала получит актуальные цены только для нужного вида, а затем аккуратно «приклеит» их к справочнику номенклатуры. Если цены нет — останется пустое место (NULL), но сама номенклатура не исчезнет.
Чтобы в отчете вместо пустых ячеек (или для корректной фильтрации) выводился ноль, необходимо использовать функцию ЕСТЬNULL. Посмотрим на пример в секции ВЫБРАТЬ:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Номенклатура,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
Функция ЕСТЬNULL(Поле, 0) проверяет значение: если там NULL, она возвращает 0, в противном случае — само значение поля. Это позволяет визуально отображать нулевую цену для товаров, которые не числятся в регистре.
Если задача стоит вывести только те товары, у которых цена не задана, мы должны проверять именно наличие связи с регистром. Рассмотрим два способа реализации этого в коде запроса:
Способ А (проверка на NULL):
ГДЕ
ЦеныНоменклатурыСрезПоследних.Цена ЕСТЬ NULL
Способ Б (использование ЕСТЬNULL в условии):
ГДЕ
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) = 0
Обратите внимание: если вы хотите видеть все товары (и с ценами, и без), секцию ГДЕ с фильтрами по цене нужно вообще исключить.
С учетом всех правок и структуры запроса из конфигурации «Розница 2.3», итоговый код будет выглядеть следующим образом. Мы объединим получение остатков, штрихкодов и цен, сохраняя целостность списка номенклатуры.
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Наименование КАК Наименование,
ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК Остаток,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена,
ЦеныНоменклатурыСрезПоследних.ВидЦены КАК ВидЦены
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК ТоварыНаСкладахОстатки
ПО (ТоварыНаСкладахОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
ГДЕ
НЕ СправочникНоменклатура.ЭтоГруппа
// Если нужно вывести только БЕЗ цен, раскомментируйте строку ниже:
// И ЦеныНоменклатурыСрезПоследних.Цена ЕСТЬ NULL
Иногда даже идеально написанный запрос не дает результата из-за настроек самой СКД. Выясним, на что обратить внимание в конструкторе схемы компоновки данных:
Цена. Если у него стоит флаг «Обязательное», СКД может самостоятельно оптимизировать запрос, удалив строки, где это поле не заполнено. Флаг должен быть снят.&Период в настройках СКД (вкладка «Параметры») заполнены. Если период не задан, виртуальная таблица может вернуть пустой результат.ГДЕ на основе пользовательских отборов. Если пользователь в отчете укажет фильтр «Цена > 0», товары без цен снова исчезнут. Чтобы этого избежать, можно использовать предопределенные отборы в настройках самого отчета.Проанализировав вышеописанные шаги, мы видим, что решение проблемы кроется в понимании механики работы NULL и специфики виртуальных таблиц 1С. Использование ЛЕВОЕ СОЕДИНЕНИЕ вместе с ЕСТЬNULL и вынос условий в параметры таблицы гарантирует, что ни одна карточка товара не будет потеряна в отчете.