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