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