Как в запросе 1С получить уникальные записи по одному полю без повторений

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

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

Почему не подходит оператор ВЫБРАТЬ РАЗЛИЧНЫЕ

Первое, что часто пробуют разработчики — установка флажка «Без повторяющихся» на вкладке «Дополнительно» в Конструкторе запросов, что добавляет в текст оператор ВЫБРАТЬ РАЗЛИЧНЫЕ. Проанализируем, как он функционирует.

Оператор РАЗЛИЧНЫЕ проверяет уникальность всей строки целиком по всем выбранным колонкам. Если в выборке присутствуют поля Номенклатура и Штрихкод, а у одного товара заданы разные коды (например, «Товар 1» — «111» и «Товар 1» — «222»), то для СУБД это две абсолютно разные строки. В результате оператор РАЗЛИЧНЫЕ оставит обе записи, и дублирование номенклатуры устранить не удастся.

Решение задачи: использование группировки и агрегатных функций

Чтобы гарантированно оставить только одну строку на каждую позицию номенклатуры, необходимо сгруппировать выборку по целевому полю, а для остальных колонок применить агрегатную функцию (например, МАКСИМУМ или МИНИМУМ). Таким образом мы явно указываем платформе, какое именно значение из нескольких доступных нужно выбрать.

Посмотрим на базовый пример запроса к регистру сведений:


ВЫБРАТЬ
    Штрихкоды.Номенклатура КАК Номенклатура,
    МАКСИМУМ(Штрихкоды.Штрихкод) КАК Штрихкод
ИЗ
    РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
СГРУППИРОВАТЬ ПО
    Штрихкоды.Номенклатура

В этом запросе поле Номенклатура становится ключом группировки, а функция МАКСИМУМ(Штрихкоды.Штрихкод) берет наибольшее строковое значение штрихкода для каждого товара, исключая дубли в результирующей таблице.

Причина ошибки «Поле не входит в группу» и ее исправление

При ручном написании запроса или некорректном сохранении схемы часто возникает ошибка: «Поле не входит в группу...». Выясним причину ее появления.

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

Разберем по шагам, как правильно настроить такой запрос в визуальном Конструкторе запросов:

  1. На вкладке «Таблицы и поля» выберите нужную таблицу (например, РегистрСведений.ШтрихкодыНоменклатуры) и перенесите в список выбранных полей Номенклатура и Штрихкод.
  2. Перейдите на вкладку «Группировка».
  3. В левое поле «Группируемые поля» добавьте поле Номенклатура.
  4. В правое поле «Суммируемые поля» добавьте поле Штрихкод и выберите для него функцию Максимум или Минимум.

Получение сопутствующих реквизитов через временную таблицу

Иногда требуется получить не только один реквизит, но и целую строку связанных данных (например, характеристику, упаковку и штрихкод), соответствующих выбранному значению. Если применить МАКСИМУМ ко всем полям независимо, данные могут «перемешаться» из разных записей регистра. Рассмотрим, как решить эту задачу с помощью пакета запросов:


ВЫБРАТЬ
    Штрихкоды.Номенклатура КАК Номенклатура,
    МАКСИМУМ(Штрихкоды.Штрихкод) КАК Штрихкод
ПОМЕСТИТЬ ВТ_МаксимальныеШтрихкоды
ИЗ
    РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
СГРУППИРОВАТЬ ПО
    Штрихкоды.Номенклатура

ИНДЕКСИРОВАТЬ ПО
    Номенклатура,
    Штрихкод
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.Номенклатура КАК Номенклатура,
    ВТ.Штрихкод КАК Штрихкод,
    Штрихкоды.Характеристика КАК Характеристика,
    Штрихкоды.Упаковка КАК Упаковка
ИЗ
    ВТ_МаксимальныеШтрихкоды КАК ВТ
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        ПО ВТ.Номенклатура = Штрихкоды.Номенклатура
        И ВТ.Штрихкод = Штрихкоды.Штрихкод

В первом запросе пакета мы определяем уникальную пару Номенклатура — Штрихкод и индексируем временную таблицу. Во втором запросе связываем ее с исходным регистром через ВНУТРЕННЕЕ СОЕДИНЕНИЕ, что позволяет получить целостные данные строки без нарушения логики.

Оконные функции в современных версиях платформы

В версиях платформы «1С:Предприятие» начиная с 8.3.27 доступна поддержка оконных функций. Это позволяет нумеровать строки внутри группы и отбирать первую запись без применения временных таблиц:


ВЫБРАТЬ
    Подзапрос.Номенклатура КАК Номенклатура,
    Подзапрос.Штрихкод КАК Штрихкод
ИЗ
    (ВЫБРАТЬ
        Штрихкоды.Номенклатура КАК Номенклатура,
        Штрихкоды.Штрихкод КАК Штрихкод,
        ROW_NUMBER() OVER (PARTITION BY Штрихкоды.Номенклатура УПОРЯДОЧИТЬ ПО Штрихкоды.Штрихкод) КАК НомерСтроки
    ИЗ
        РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды) КАК Подзапрос
ГДЕ
    Подзапрос.НомерСтроки = 1

Рекомендации по оптимизации производительности

При работе с большими регистрами сведений следует учитывать следующие правила:

  1. Ограничивайте выборку условиями: избегайте полного сканирования таблицы регистра. Если обработка выполняется для конкретного списка позиций, всегда используйте условие ГДЕ Штрихкоды.Номенклатура В (&МассивНоменклатуры).
  2. Индексируйте временные таблицы: при объединении временных таблиц обязательно указывайте ИНДЕКСИРОВАТЬ ПО по полям соединения, чтобы снизить нагрузку на СУБД.
  3. Приведение типов строк: если группируемое или агрегируемое строковое поле имеет неограниченную длину, СУБД выдаст ошибку. В таком случае предварительно ограничьте длину с помощью конструкции ВЫРАЗИТЬ(Поле КАК СТРОКА(100)).
← На главную