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