← Назад к вопросам

Запрос: товары с уникальной ценой

2.0 Middle🔥 161 комментариев
#Запросы и оптимизация

Условие

Дана таблица из двух колонок: Товар и Цена. Нужно выбрать товары, у которых цена уникальна (встречается ровно один раз).

Реализуйте решение несколькими способами (минимум два варианта запроса).

Пример

Входные данные:

ТоварЦена
А100
Б200
В100
Г300

Выход: Б (цена 200), Г (цена 300)

Товары А и В имеют одинаковую цену 100, поэтому не включаются в результат.

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Обзор задачи

Эта задача требует определения товаров с уникальными ценами — то есть цены, которые встречаются только один раз в таблице. Это тест на понимание:

  • GROUP BY и агрегирующих функций (COUNT)
  • HAVING условий
  • Различных подходов к решению одной задачи
  • Оптимизации запросов

Способ 1: С использованием GROUP BY и HAVING с COUNT

Выбрать
    Товар.Ссылка,
    Товар.Наименование Как Товар,
    ЦенаТовара.Цена
Из
    Справочник.Товар Как Товар
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как ЦенаТовара
        На Товар.Ссылка = ЦенаТовара.Товар
Группировать По
    Товар.Ссылка,
    Товар.Наименование,
    ЦенаТовара.Цена
Имеющие
    КОЛИЧЕСТВО(*) = 1
Упорядочить По
    Товар.Наименование

Описание: Группируем по товару и цене, затем отбираем только те группы, где количество совпадений = 1.

Способ 2: С подзапросом для подсчёта ценовых дубликатов

Выбрать
    Т.Ссылка,
    Т.Наименование Как Товар,
    Ц.Цена
Из
    Справочник.Товар Как Т
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как Ц
        На Т.Ссылка = Ц.Товар
Где
    (Выбрать КОЛИЧЕСТВО(*)
     Из РегистрСведений.ЦенаТовара Как ЦеныВнут
     Где ЦеныВнут.Цена = Ц.Цена) = 1
Упорядочить По
    Т.Наименование

Описание: Для каждого товара в подзапросе считаем, сколько раз встречается его цена во всей таблице. Отбираем товары, где это значение = 1.

Способ 3: Через виртуальную таблицу с промежуточным подсчётом

Выбрать
    Товар.Ссылка,
    Товар.Наименование,
    Цены.Цена
Из
    (
        Выбрать
            ЦенаТовара.Товар,
            ЦенаТовара.Цена,
            КОЛИЧЕСТВО(*) Как КоличествоТоваров
        Из
            РегистрСведений.ЦенаТовара Как ЦенаТовара
        Группировать По
            ЦенаТовара.Цена
    ) Как СтатистикаЦен
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как Цены
        На СтатистикаЦен.Цена = Цены.Цена
    Внутреннее Соединение Справочник.Товар Как Товар
        На Цены.Товар = Товар.Ссылка
Где
    СтатистикаЦен.КоличествоТоваров = 1
Упорядочить По
    Товар.Наименование

Описание: Создаём виртуальную таблицу со статистикой по ценам, затем присоединяем её к основной таблице.

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

Выбрать Различные
    Т.Ссылка,
    Т.Наименование,
    ЦеныГруп.Цена
Из
    (
        Выбрать
            ЦенаТовара.Цена,
            КОЛИЧЕСТВО(*) Как КолТоваров
        Из
            РегистрСведений.ЦенаТовара Как ЦенаТовара
        Группировать По
            ЦенаТовара.Цена
        Имеющие
            КОЛИЧЕСТВО(*) = 1
    ) Как ЦеныГруп
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как Цены
        На ЦеныГруп.Цена = Цены.Цена
    Внутреннее Соединение Справочник.Товар Как Т
        На Цены.Товар = Т.Ссылка
Упорядочить По
    Т.Наименование

Описание: Находим уникальные цены в подзапросе (HAVING COUNT = 1), затем присоединяем товары с этими ценами.

Способ 5: Использование оконных функций (если поддерживается версия 1С)

Выбрать
    Товар.Ссылка,
    Товар.Наименование,
    Цены.Цена
Из
    Справочник.Товар Как Товар
    Внутреннее Соединение
        (
            Выбрать
                Товар,
                Цена,
                КОЛИЧЕСТВО(*) Над (Раздел Все Упорядочить По Цена) Как КолценыВсего,
                КОЛИЧЕСТВО(*) Над (Раздел По Цена) Как КолценыВГруппе
            Из
                РегистрСведений.ЦенаТовара
        ) Как ЦенаТовара
        На Товар.Ссылка = ЦенаТовара.Товар
Где
    ЦенаТовара.КолценыВГруппе = 1
Упорядочить По
    Товар.Наименование

Способ 6: Через антисоединение (NOT IN)

Выбрать
    Товар.Ссылка,
    Товар.Наименование Как Товар,
    Цена.Цена
Из
    Справочник.Товар Как Товар
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как Цена
        На Товар.Ссылка = Цена.Товар
Где
    Цена.Цена Не В
        (
            Выбрать
                ЦЦена.Цена
            Из
                РегистрСведений.ЦенаТовара Как ЦЦена
            Группировать По
                ЦЦена.Цена
            Имеющие
                КОЛИЧЕСТВО(*) > 1
        )
Упорядочить По
    Товар.Наименование

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

Рекомендуемые варианты

Для простоты и читаемости — Способ 1:

Выбрать
    Товар.Ссылка,
    Товар.Наименование Как Товар,
    ЦенаТовара.Цена
Из
    Справочник.Товар Как Товар
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как ЦенаТовара
        На Товар.Ссылка = ЦенаТовара.Товар
Группировать По
    Товар.Ссылка,
    Товар.Наименование,
    ЦенаТовара.Цена
Имеющие
    КОЛИЧЕСТВО(*) = 1
Упорядочить По
    Товар.Наименование

Для гибкости и отладки — Способ 2:

Выбрать
    Т.Ссылка,
    Т.Наименование Как Товар,
    Ц.Цена
Из
    Справочник.Товар Как Т
    Внутреннее Соединение РегистрСведений.ЦенаТовара Как Ц
        На Т.Ссылка = Ц.Товар
Где
    (Выбрать КОЛИЧЕСТВО(*)
     Из РегистрСведений.ЦенаТовара Как ЦеныВнут
     Где ЦеныВнут.Цена = Ц.Цена) = 1
Упорядочить По
    Т.Наименование

Реализация в коде 1С

Процедура НайтиТоварыСУникальнымиЦенами()
    
    ТекстЗапроса = "Выбрать
        |    Товар.Ссылка,
        |    Товар.Наименование Как Товар,
        |    ЦенаТовара.Цена
        |Из
        |    Справочник.Товар Как Товар
        |    Внутреннее Соединение РегистрСведений.ЦенаТовара Как ЦенаТовара
        |        На Товар.Ссылка = ЦенаТовара.Товар
        |Группировать По
        |    Товар.Ссылка,
        |    Товар.Наименование,
        |    ЦенаТовара.Цена
        |Имеющие
        |    КОЛИЧЕСТВО(*) = 1
        |Упорядочить По
        |    Товар.Наименование";
    
    Запрос = Новый Запрос(ТекстЗапроса);
    РезультатЗапроса = Запрос.Выполнить();
    ТаблицаРезультата = РезультатЗапроса.Выгрузить();
    
    Для каждого Строка Из ТаблицаРезультата Цикл
        Сообщить("Товар: " + Строка.Товар + ", Цена: " + Строка.Цена);
    КонецЦикла;
    
КонецПроцедуры

Тестирование на примере

Для входных данных:

А - 100
Б - 200
В - 100
Г - 300

Ожидаемый результат:

Б - 200 (цена встречается 1 раз)
Г - 300 (цена встречается 1 раз)

Цены, которые НЕ попадут в результат:

  • 100 (встречается 2 раза: у товара А и В)

Сравнение подходов

СпособСложностьЧитаемостьПроизводительностьКогда использовать
1ПростойХорошаяХорошаяProduction код, простые случаи
2СреднийХорошаяСредняяОтладка, небольшие таблицы
3СложныйСредняяХорошаяБольшие объёмы данных
4СреднийСредняяХорошаяКогда нужна промежуточная статистика
5СложныйХорошаяОтличнаяБольшие таблицы (если версия поддерживает)
6СреднийХорошаяСредняяКогда удобнее искать "исключения"

Ключевые моменты

  1. GROUP BY + HAVING — основной паттерн для работы с группировками
  2. КОЛИЧЕСТВО(*) — подсчитывает количество строк в группе
  3. Подзапросы — позволяют использовать текущие значения во WHERE
  4. Внутреннее Соединение — гарантирует только товары с ценами
  5. Упорядочить По — для удобства просмотра результатов
Запрос: товары с уникальной ценой | PrepBro