Как в запросе 1С установить условие на сгруппированные данные или итоги?

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

Часто при работе с запросами в 1С возникает задача отфильтровать результат не по значению поля в каждой отдельной строке, а по итоговому, агрегированному значению после группировки. Например, найти все товары, которых продано больше 100 штук, или, как в нашем случае, найти элементы справочника с одинаковыми наименованиями, то есть дубли. Стандартный оператор ГДЕ здесь не поможет, так как он работает до группировки данных.

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

Ключевое различие: ГДЕ и ИМЕЮЩИЕ

Прежде чем перейти к решениям, давайте выясним причину, почему нельзя просто написать условие в секции ГДЕ. В языке запросов 1С существует четкое разделение обязанностей между двумя операторами фильтрации:

  1. ГДЕ (WHERE) — этот оператор применяется к строкам таблицы до того, как они будут сгруппированы. Он фильтрует исходный набор данных. Например, можно выбрать только элементы из определенной группы справочника или документы за конкретный период.
  2. ИМЕЮЩИЕ (HAVING) — этот оператор создан специально для нашей задачи. Он применяется к результатам после того, как данные были сгруппированы с помощью СГРУППИРОВАТЬ ПО и к ним были применены агрегатные функции, такие как КОЛИЧЕСТВО(), СУММА(), СРЕДНЕЕ() и другие.

Таким образом, для фильтрации по итогам нам нужен именно оператор ИМЕЮЩИЕ. Рассмотрим подробнее, как его использовать.

Решение 1: Найти наименования-дубли и их количество

Это самый простой и быстрый способ, если наша цель — просто увидеть, какие наименования в справочнике повторяются и сколько раз. Нам не нужны ссылки на сами элементы, только информация о факте дублирования.

Разберем по шагам логику запроса:

  1. Берем данные из нужного нам справочника (в примере это условный Справочник.Справочник2).
  2. Группируем все записи по полю Наименование. В результате для каждого уникального наименования мы получим одну строку.
  3. Для каждой такой сгруппированной строки подсчитываем количество элементов с помощью агрегатной функции КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка). Это даст нам число дублей для каждого наименования.
  4. С помощью оператора ИМЕЮЩИЕ отбираем только те группы (наименования), у которых подсчитанное количество больше единицы. Это и будут наши дубли.

Посмотрим на пример кода, который реализует эту логику:


ВЫБРАТЬ
	Справочник2.Наименование КАК Наименование,
	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Справочник2.Ссылка) КАК КоличествоДублей
ИЗ
	Справочник.Справочник2 КАК Справочник2

СГРУППИРОВАТЬ ПО
	Справочник2.Наименование

ИМЕЮЩИЕ
	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Справочник2.Ссылка) > 1

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

Решение 2: Получить ссылки на все элементы-дубли

Чаще всего нам нужно не просто узнать о наличии дублей, а получить ссылки на конкретные повторяющиеся элементы, чтобы, например, обработать их или пометить на удаление. В этом случае задача усложняется, и решить ее одним запросом не получится. Здесь мы применим подход с использованием временных таблиц.

Алгоритм будет состоять из двух шагов:

  1. Шаг 1: Найти наименования-дубли. С помощью первого запроса, очень похожего на предыдущее решение, мы находим все наименования, которые повторяются, и помещаем их во временную таблицу.
  2. Шаг 2: Выбрать элементы по этим наименованиям. Вторым запросом мы обращаемся к нашему справочнику еще раз и выбираем ссылки на все элементы, наименования которых содержатся в созданной нами временной таблице.

Рассмотрим этот двухэтапный запрос подробнее:


ВЫБРАТЬ
	Справочник2.Наименование КАК Наименование
ПОМЕСТИТЬ ВременнаяТаблицаДублиСправочников
ИЗ
	Справочник.Справочник2 КАК Справочник2

СГРУППИРОВАТЬ ПО
	Справочник2.Наименование

ИМЕЮЩИЕ
	КОЛИЧЕСТВО(*) > 1
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Справочник2.Ссылка КАК Ссылка
ИЗ
	Справочник.Справочник2 КАК Справочник2
ГДЕ
	Справочник2.Наименование В (ВЫБРАТЬ
		ВременнаяТаблицаДублиСправочников.Наименование
	ИЗ
		ВременнаяТаблицаДублиСправочников)

Проанализируем, что здесь происходит:

В результате мы получаем полный список ссылок на все элементы, у которых есть дубли по наименованию. Это самый надежный и универсальный способ для решения подобных задач.

← К списку