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