Почему в запросе 1С не суммируются одинаковые строки номенклатуры?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При написании запросов во встроенном языке 1С разработчики нередко сталкиваются с ситуацией, когда предложение СГРУППИРОВАТЬ ПО визуально не объединяет одинаковые позиции. В результирующей таблице строки выводятся раздельно, несмотря на то что в коде запроса указаны агрегатные функции, такие как СУММА(Количество) или СУММА(Сумма). Разберем по шагам, почему возникает такое поведение платформы и как правильно локализовать и устранить эту проблему.

Причина: различие ссылок при одинаковом визуальном представлении

Проанализируем типовую ситуацию. В запросе выбираются строки табличной части документа, группируемые по номенклатуре, ссылке на документ и контрагенту:


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

При выполнении этого запроса в выборке могут оставаться две одинаковые на первый взгляд строки с одной и той же номенклатурой. Главная причина кроется в механизме работы ссылочного типа данных в платформе 1С:Предприятие. СУБД выполняет группировку не по наименованию или коду, а по внутреннему 128-битному идентификатору — уникальному идентификатору (GUID) ссылки.

Если в информационной базе по ошибке или в результате обмена данными были созданы два элемента справочника Номенклатура с идентичным кодом и наименованием, для пользователя в интерфейсе они выглядят одинаково, но для механизма запросов это две абсолютно разные записи. СУБД распределяет их по отдельным группам, из-за чего агрегация не происходит.

Методы диагностики и проверки уникальности ссылок

Выясним причину разделения строк на практике. Для этого выполним несколько проверочных шагов:

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

Оптимизация текста запроса и расчет цен

Рассмотрим структуру исходного запроса подробнее и устраним потенциальные проблемы с производительностью и корректностью данных:

  1. Исключение неявных соединений: обращение через точку к реквизитам шапки из табличной части вида ПоступлениеТоваровУслугТовары.Ссылка.Контрагент генерирует на уровне СУБД дополнительное левое соединение (LEFT JOIN). Для оптимизации рекомендуется либо обращаться напрямую к таблице шапки документа через явное соединение, либо отбирать данные с предварительной фильтрацией документов.
  2. Корректный расчет цены: применение функции СУММА(Цена) лишено математического и учетного смысла, так как суммирование цен разных строк дает некорректную величину. Для расчета средней или средневзвешенной цены в запросе следует вычислять отношение общей суммы к общему количеству:

ВЫБОР
    КОГДА СУММА(ПоступлениеТоваровУслугТовары.Количество) = 0 ТОГДА 0
    ИНАЧЕ СУММА(ПоступлениеТоваровУслугТовары.Сумма) / СУММА(ПоступлениеТоваровУслугТовары.Количество)
КОНЕЦ КАК СредняяЦена

Альтернативная группировка в оперативной памяти

Если в процессе разработки данные уже получены в виде таблицы значений без группировки на стороне СУБД, агрегировать одинаковые строки можно средствами встроенного языка с помощью метода Свернуть():


ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
ТаблицаРезультата.Свернуть("Ссылка, Контрагент, Номенклатура", "Количество, Сумма");

Важно помнить: метод Свернуть() также выполняет сравнение ссылочных колонок по внутреннему идентификатору. Если проблема заключалась в наличии физических дублей элементов в справочнике, свертка таблицы значений не объединит эти строки до тех пор, пока ссылки не будут приведены к единому элементу.

← На главную