Почему не работает группировка по единице измерения в табличной части 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов и написании запросов в системе «1С:Предприятие» программисты часто сталкиваются с неожиданным поведением платформы: группировка в запросе по полю единицы измерения из табличной части документа не «схлопывает» строки. Визуально в результате запроса мы видим одинаковые значения (например, «шт» или «кг»), но платформа упорно выводит их отдельными строками для каждой номенклатурной позиции. В итоге группировка по единице измерения отрабатывает точно так же, как группировка по самой номенклатуре.

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем архитектуру хранения единиц измерения в конфигурациях «1С» и рассмотрим несколько эффективных способов решения этой задачи в запросах, таблицах значений и СКД.

Выясняем причину: особенности архитектуры справочников «1С»

Для того чтобы понять, почему СУБД не может сгруппировать одинаковые на первый взгляд единицы измерения, нам необходимо заглянуть в структуру метаданных конфигурации. В классических конфигурациях «1С» (таких как «Управление торговлей 10.3», «Управление производственным предприятием 1.3», «Комплексная автоматизация 1.1» и других решениях на обычных формах) учет единиц измерения реализован с помощью связки двух разных справочников:

  1. Справочник «Классификатор единиц измерения» (Справочник.КлассификаторЕдиницИзмерения). Это плоский общесистемный классификатор (соответствующий ОКЕИ), в котором хранятся глобальные единицы измерения («шт», «кг», «л», «м» и т. д.). Данный справочник не подчинен другим объектам.
  2. Справочник «Единицы измерения» (Справочник.ЕдиницыИзмерения). Этот справочник является подчиненным справочнику Справочник.Номенклатура. Он предназначен для хранения индивидуальных упаковок, коэффициентов пересчета и весовых характеристик конкретного товара.

В табличных частях документов (например, в документе «Маршрутный лист» или «Реализация товаров и услуг») реквизит ЕдиницаИзмерения имеет ссылочный тип подчиненного справочника — СправочникСсылка.ЕдиницыИзмерения.

Когда мы создаем карточку номенклатуры «Товар А» и указываем для нее базовую единицу «шт», система создает в подчиненном справочнике уникальную запись с уникальным идентификатором (GUID). Когда мы создаем «Товар Б» и также назначаем ему базовую единицу «шт», система создает еще одну, совершенно другую запись в таблице базы данных со своим собственным GUID.

Таким образом, с точки зрения СУБД, единица измерения «шт» для «Товара А» и единица измерения «шт» для «Товара Б» — это две абсолютно разные сущности с уникальными ссылками. При попытке сгруппировать запрос по полю оМаршрутныйЛистТовары.ЕдиницаИзмерения платформа сравнивает именно GUID записей. Так как они различаются, группировка по ссылке фактически превращается в группировку по уникальным парам «Товар - Единица измерения».

Решение 1. Группировка в запросе по классификатору (рекомендуемый способ)

Проанализируем структуру подчиненного справочника ЕдиницыИзмерения. В нем присутствует стандартный реквизит ЕдиницаПоКлассификатору, который ссылается на общий классификатор единиц измерения. Поскольку элементы общего классификатора едины для всей информационной базы, ссылки на них у разных товаров будут совпадать.

Рассмотрим, как правильно составить запрос с группировкой по общему классификатору через обращение к реквизиту подчиненного справочника:


ВЫБРАТЬ
    оМаршрутныйЛистТовары.ЕдиницаИзмерения.ЕдиницаПоКлассификатору КАК ЕдиницаИзмерения,
    СУММА(оМаршрутныйЛистТовары.Количество) КАК Количество
ИЗ
    Документ.оМаршрутныйЛист.Товары КАК оМаршрутныйЛистТовары
ГДЕ
    оМаршрутныйЛистТовары.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    оМаршрутныйЛистТовары.ЕдиницаИзмерения.ЕдиницаПоКлассификатору

Преимущества данного метода: Сравнение и группировка на уровне СУБД происходят по индексированным ссылочным полям (GUID глобального классификатора), что обеспечивает максимальную скорость выполнения запроса. Это наиболее архитектурно правильный способ решения проблемы.

Решение 2. Группировка по наименованию единицы измерения

Если в вашей конфигурации по какой-то причине отсутствует реквизит связи с классификатором или вам требуется быстро вывести сгруппированные данные без привязки к справочнику-классификатору, можно выполнить группировку по текстовому представлению (наименованию) единицы измерения.

Посмотрим на пример такого запроса:


ВЫБРАТЬ
    оМаршрутныйЛистТовары.ЕдиницаИзмерения.Наименование КАК ЕдиницаНаименование,
    СУММА(оМаршрутныйЛистТовары.Количество) КАК Количество
ИЗ
    Документ.оМаршрутныйЛист.Товары КАК оМаршрутныйЛистТовары
ГДЕ
    оМаршрутныйЛистТовары.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    оМаршрутныйЛистТовары.ЕдиницаИзмерения.Наименование

Важные нюансы использования: Этот способ имеет очевидные недостатки. Сравнение строковых полей в СУБД выполняется медленнее, чем сравнение ссылок. Кроме того, если пользователи случайно запишут наименования с разным регистром или лишними пробелами (например, «шт» и «шт. »), СУБД распределит их по разным строкам.

Решение 3. Свертка таблицы значений (ТЗ) на клиенте или сервере

Аналогичная проблема возникает, когда разработчики пытаются использовать метод ТаблицаЗначений.Свернуть() во встроенном языке «1С». Если колонка содержит ссылки на подчиненный справочник, то при вызове метода строки не будут объединены, так как ссылки в них уникальны.

Разберем по шагам, как правильно свернуть таблицу значений программно:

  1. Добавим в исходную таблицу значений вспомогательную колонку, которая будет хранить ссылку на общий классификатор единиц измерения.
  2. В цикле заполним новую колонку значениями общего классификатора, обращаясь к реквизиту через точку.
  3. Выполним свертку таблицы значений по новой колонке.

Посмотрим на пример реализации данного алгоритма в коде:


// Предположим, что ТаблицаТоваров получена из табличной части документа
// Добавим типизированную колонку для хранения общей единицы
ТипКлассификатора = Новый ОписаниеТипов("СправочникСсылка.КлассификаторЕдиницИзмерения");
ТаблицаТоваров.Колонки.Добавить("ЕдиницаКлассификатора", ТипКлассификатора);

// Заполняем колонку значениями общего классификатора
Для Каждого СтрокаТаблицы Из ТаблицаТоваров Цикл
    СтрокаТаблицы.ЕдиницаКлассификатора = СтрокаТаблицы.ЕдиницаИзмерения.ЕдиницаПоКлассификатору;
КонецЦикла;

// Теперь мы можем корректно свернуть таблицу значений
ТаблицаТоваров.Свернуть("ЕдиницаКлассификатора", "Количество, Сумма");

Решение 4. Особенности настройки группировок в СКД

При использовании Системы компоновки данных (СКД) разработчики часто сталкиваются с тем, что даже при добавлении поля ЕдиницаИзмерения в группировку отчета, результат все равно выводится детально по номенклатуре. Это происходит потому, что СКД по умолчанию оперирует ссылками объектов, даже если на экран выводится их строковое представление.

Чтобы решить эту проблему в СКД, рекомендуется использовать один из следующих подходов:

Как эта проблема решена в современных конфигурациях?

В конфигурациях нового поколения на управляемых формах (таких как «1С:ERP Управление предприятием», «Управление торговлей 11», «Комплексная автоматизация 2») архитекторы фирмы «1С» полностью отказались от использования подчиненных справочников для хранения базовых единиц измерения.

В современных конфигурациях используется справочник Справочник.УпаковкиЕдиницыИзмерения. Все базовые единицы измерения хранятся непосредственно в нем как глобальные элементы, единые для всей информационной базы. Для учета индивидуальных особенностей товаров (коробок, паллет) применяется независимый механизм упаковок, привязанный к наборам упаковок. Благодаря этому изменению, группировка по единицам измерения в современных запросах работает «из коробки» без необходимости обращения к реквизитам через точку.

← На главную