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