Как посчитать количество строк с уникальным сочетанием Номенклатура-ХарактеристикаНоменклатуры в 1С

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

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

Анализ проблемы: почему РАЗЛИЧНЫЕ не всегда помогает

Рассмотрим типичную ситуацию. В документе РеализацияТоваровУслуг в табличной части Товары может быть несколько строк с одной и той же номенклатурой, но разными характеристиками. Или, что еще чаще, одна и та же пара Номенклатура-Характеристика может дублироваться в разных строках (например, из-за разных складов или партий). Нам же нужно получить число именно уникальных пар для конкретного документа.

Попытка использовать РАЗЛИЧНЫЕ напрямую в запросе с агрегатными функциями часто приводит к ошибкам. Давайте проанализируем пример кода, который часто пытаются использовать начинающие разработчики:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Номенклатура,
    ХарактеристикаНоменклатуры,
    1 КАК Количество,
    Ссылка
ПОМЕСТИТЬ ГруппыСтрок    
ИЗ
    Документ.РеализацияТоваровУслуг.Товары
;
ВЫБРАТЬ
    Ссылка,
    СУММА(Количество) КАК Кол
ИЗ
    ГруппыСтрок
СГРУППИРОВАТЬ ПО
    Ссылка

Казалось бы, логика верна: сначала мы отбираем уникальные тройки (Номенклатура, Характеристика, Ссылка) и помечаем каждую единицей, а затем суммируем эти единицы. Однако на практике разработчики сталкиваются с тем, что результат в консоли запросов может меняться в зависимости от того, какие поля выбраны в финальном запросе. Это происходит из-за особенностей оптимизации планов запросов СУБД и того, как платформа 1С интерпретирует временные таблицы.

Решение №1: Использование СГРУППИРОВАТЬ ПО (Рекомендуемый способ)

Наиболее надежный и прозрачный способ получить уникальные записи во временную таблицу — это использование группировки вместо ключевого слова РАЗЛИЧНЫЕ. Это позволяет СУБД более эффективно построить план запроса.

Разберем этот метод по шагам:

  1. Создаем временную таблицу, в которой группируем строки по всем значимым измерениям (Документ, Номенклатура, Характеристика).
  2. Во втором запросе просто считаем количество записей, оставшихся после группировки.

ВЫБРАТЬ
    ТЧ.Ссылка КАК ДокументСсылка,
    ТЧ.Номенклатура КАК Номенклатура,
    ТЧ.ХарактеристикаНоменклатуры КАК Характеристика
ПОМЕСТИТЬ ВТ_УникальныеСтроки
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
ГДЕ
    ТЧ.Ссылка = &СсылкаНаДокумент
СГРУППИРОВАТЬ ПО
    ТЧ.Ссылка,
    ТЧ.Номенклатура,
    ТЧ.ХарактеристикаНоменклатуры
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.ДокументСсылка,
    КОЛИЧЕСТВО(*) КАК КоличествоУникальныхПар
ИЗ
    ВТ_УникальныеСтроки КАК ВТ
СГРУППИРОВАТЬ ПО
    ВТ.ДокументСсылка

В данном примере мы гарантированно получаем по одной строке на каждую уникальную комбинацию. Использование КОЛИЧЕСТВО(*) во втором запросе вернет нам точное число таких комбинаций для документа.

Решение №2: Использование вложенных запросов

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


ВЫБРАТЬ
    ВложенныйЗапрос.Ссылка,
    КОЛИЧЕСТВО(ВложенныйЗапрос.Номенклатура) КАК КолУникальных
ИЗ
    (ВЫБРАТЬ РАЗЛИЧНЫЕ
        Товары.Ссылка КАК Ссылка,
        Товары.Номенклатура КАК Номенклатура,
        Товары.ХарактеристикаНоменклатуры КАК Характеристика
    ИЗ
        Документ.РеализацияТоваровУслуг.Товары КАК Товары) КАК ВложенныйЗапрос
СГРУППИРОВАТЬ ПО
    ВложенныйЗапрос.Ссылка

Важный нюанс: вложенные запросы с РАЗЛИЧНЫЕ могут работать медленнее на больших объемах данных, чем временные таблицы с индексами. Поэтому для табличных частей реальных документов первый способ предпочтительнее.

Почему консоль запросов может "врать"?

Проанализируем ситуацию, описанную в обсуждении: почему при добавлении полей в выборку количество строк меняется? Это типичная проблема при работе в Консоли запросов (особенно в толстом клиенте).

Выясним причины такого поведения:

Работа с характеристиками и NULL

При подсчете уникальных пар важно учитывать, как система обрабатывает пустые характеристики. Рассмотрим ситуацию: в одной строке характеристика не заполнена (пустая ссылка), а в другой строке поле может содержать NULL (например, после левого соединения).

Для платформы 1С NULL и ПустаяСсылка — это разные значения. Если вы хотите, чтобы строки без характеристик считались одной группой, проанализируем использование функции ЕСТЬNULL:


ВЫБРАТЬ
    ТЧ.Номенклатура,
    ЕСТЬNULL(ТЧ.ХарактеристикаНоменклатуры, ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)) КАК Характеристика
...

Это обеспечит единообразие данных перед группировкой и гарантирует, что подсчет будет корректным.

Выводы

Для гарантированного получения количества уникальных строк в 1С всегда придерживайтесь правила двух этапов:

  1. Сначала "схлопните" дубликаты во временную таблицу с помощью СГРУППИРОВАТЬ ПО.
  2. Затем выполните агрегацию (подсчет) по результатам этой временной таблицы.

Такой подход делает ваш код устойчивым к особенностям работы СУБД, легко читаемым и простым в отладке. Помните, что использование РАЗЛИЧНЫЕ удобно для простых выборок, но в сложных пакетах запросов оно может вести себя непредсказуемо.

← На главную