Как агрегатная функция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ) сравнивает ссылки в запросах 1С?

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

При работе с языком запросов 1С разработчики иногда сталкиваются с ситуацией, когда двух разных элементов справочника с одинаковыми наименованиями агрегатная функция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) будто бы не различает. Возникает естественный вопрос: как именно платформа сравнивает значения ссылочных типов — по их визуальному представлению (наименованию) или по уникальному идентификатору в базе данных?

В этой статье мы подробно разберем механизм работы конструкций группировки и функции КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...), выясним причину ошибочных выводов и рассмотрим способы оптимизации запросов при подсчете уникальных значений.

Принцип работы функции КОЛИЧЕСТВО(РАЗЛИЧНЫЕ) для ссылочных типов

Проанализируем базовый механизм платформы: в языке запросов 1С агрегатная функция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) всегда выполняет сравнение по внутреннему типу данных и уникальному идентификатору (GUID). Если в табличной части или справочнике присутствуют две разные ссылки, которые ссылаются на разные элементы, платформа всегда посчитает их как два разных элемента, даже если у них полностью совпадают реквизиты Наименование, Код или любые другие поля.

Сравнение по строковому представлению происходит исключительно в том случае, если разработчик явно применил к полю функцию ПРЕДСТАВЛЕНИЕ() или выполнил приведение типа через ВЫРАЗИТЬ(... КАК СТРОКА).

Анализ ошибки в запросе пользователя

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


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

Выясним причину, почему запрос вернул неожиданное значение. Проблема заключалась не в алгоритме работы КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...), а в условии отбора ГДЕ НомерСтроки > 1. Отсекая первую строку табличной части, запрос физически исключал часть данных из выборки. Из-за этого количество попавших в выборку различных значений оказавалось меньше ожидаемого.

Особенности обработки специальный значений (NULL, пустые и «битые» ссылки)

Разберем, как агрегатная функция ведет себя с особенными значениями, которые могут встретиться в базе данных:

  1. Значения NULL: Функция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) полностью игнорирует `NULL`. Если в проверяемой колонке находится `NULL`, он не попадает в итоговый подсчет.
  2. Пустые ссылки: Пустая ссылка конкретного типа (например, Справочник.Номенклатура.ПустаяСсылка()) является полноценным значением. Если в выборке встречается несколько пустых ссылок одного типа, платформа посчитает их как один уникальный элемент.
  3. «Битые» ссылки: Если объект был удален из базы данных, но ссылка на него осталась, platform хранит ее уникальный GUID. Несмотря на то что в представлении выводится <Объект не найден...>, функция посчитает каждую такую ссылку как отдельное уникальное значение, так как их GUID различаются.

Ограничения и оптимизация производительности

При использовании агрегатной функции КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) следует учитывать важные платформенные ограничения:

  1. Внутри функции разрешено указывать только одно выражение. Конструкции вида КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле1, Поле2) платформой не поддерживаются.
  2. Оператор РАЗЛИЧНЫЕ нельзя использовать для полей неограниченной длины (строки неограниченной длины, ХранилищеЗначения).

На стороне системы управления базами данных (СУБД) данная функция транслируется в конструкцию COUNT(DISTINCT ...). На больших объемах данных в табличных частях это может приводить к повышенной нагрузке. Для оптимизации производительности рекомендуем использовать двухшаговый подход с применением временных таблиц.

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


// Шаг 1: Выбираем уникальные комбинации полей во временную таблицу
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ТЧ.Ссылка КАК Ссылка,
    ТЧ.Участок КАК Участок
ПОМЕСТИТЬ ВТ_УникальныеУчастки
ИЗ
    Справочник.ДоговорыКонтрагентов.СписокУчастков КАК ТЧ;

// Шаг 2: Подсчитываем количество записей обычным КОЛИЧЕСТВО(*)
ВЫБРАТЬ
    ВТ.Ссылка КАК Ссылка,
    КОЛИЧЕСТВО(*) КАК УчастокКоличество
ИЗ
    ВТ_УникальныеУчастки КАК ВТ
СГРУППИРОВАТЬ ПО
    ВТ.Ссылка;

Такой подход с предварительным отбором через ПОМЕСТИТЬ позволяет СУБД построить более эффективный план выполнения и существенно ускорить работу запроса на больших массивах данных.

← На главную