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