К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как убрать повторяющиеся значения в запросе 1С

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

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

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

Ниже разобраны все рабочие способы с примерами кода, условия выбора между ними, типичные ошибки и методы проверки результата. Материал применим к платформе 1С:Предприятие 8.3 и актуален для любых конфигураций, использующих встроенный язык запросов.

Как работает конструкция РАЗЛИЧНЫЕ

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

ВЫБРАТЬ РАЗЛИЧНЫЕ

Товары.Номенклатура КАК Номенклатура

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Товары

ГДЕ

Товары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Запрос вернёт список номенклатуры, которая встречалась в реализациях за период, без повторов. Важно понимать: уникальность проверяется по всей комбинации выбранных полей. Если добавить в выборку поле «Количество», то строки с одинаковой номенклатурой, но разным количеством перестанут считаться дублями и обе попадут в результат.

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

Когда вместо РАЗЛИЧНЫЕ нужна группировка

Конструкция СГРУППИРОВАТЬ ПО тоже убирает дубли, но её назначение шире — она нужна, когда к сгруппированным строкам применяются агрегатные функции: СУММА, КОЛИЧЕСТВО, МАКСИМУМ, МИНИМУМ, СРЕДНЕЕ. Если вам нужно знать не просто «какие товары продавались», а «сколько каждого товара продано», группировка — единственный правильный вариант.

ВЫБРАТЬ

Товары.Номенклатура КАК Номенклатура,

СУММА(Товары.Количество) КАК Количество,

СУММА(Товары.Сумма) КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Товары

СГРУППИРОВАТЬ ПО

Товары.Номенклатура

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

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

Сравнение вариантов

РАЗЛИЧНЫЕ

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

СГРУППИРОВАТЬ ПО

Нужна, когда кроме уникальности требуются агрегаты: суммы, максимумы, количество. Тяжелее РАЗЛИЧНЫЕ при простом списке.

Свернуть() таблицы значений

Применяется после выполнения запроса, в коде. Удобен для уже полученных данных, но требует выгрузки всей выборки в память.

Устранение дублей при соединении таблиц

На практике дубли чаще всего появляются не из-за повторов в одной таблице, а из-за соединений. Классический сценарий: соединение документа с регистром, где на один документ приходится несколько записей. Каждая строка документа «размножается» на число связанных записей, и в результате одна и та же шапка документа повторяется многократно.

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

ВЫБРАТЬ

Реализация.Ссылка КАК Документ,

ЕСТЬNULL(Обороты.СуммаОборот, 0) КАК Сумма

ИЗ

Документ.РеализацияТоваровУслуг КАК Реализация

ЛЕВОЕ СОЕДИНЕНИЕ (

ВЫБРАТЬ

Обороты.Регистратор КАК Регистратор,

СУММА(Обороты.СуммаОборот) КАК СуммаОборот

ИЗ

РегистрНакопления.Продажи.Обороты КАК Обороты

СГРУППИРОВАТЬ ПО

Обороты.Регистратор

) КАК Обороты

ПО Реализация.Ссылка = Обороты.Регистратор

Такой подход гарантирует, что на один документ придётся ровно одна строка результата, и исключает задвоение сумм — ещё одну опасную ошибку, когда сумма документа умножается на количество связанных записей.

Удаление дублей вне запроса: метод Свернуть()

Иногда данные уже получены в таблицу значений, и дубли нужно убрать в коде. Для этого у таблицы значений есть метод Свернуть(). В простейшей форме он принимает два параметра: строку с именами колонок группировки и строку с именами суммируемых колонок.

ТаблицаРезультата = Запрос.Выполнить().Выгрузить();

// Оставить уникальные комбинации Номенклатура + Склад,

// суммируя количество

ТаблицаРезультата.Свернуть("Номенклатура, Склад", "Количество");

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

Выбор между свёрткой в запросе и в коде почти всегда решается в пользу запроса: СУБД выполнит группировку быстрее и не потребует передачи лишних строк на сервер 1С. Свернуть() оправдан, когда таблица собирается из нескольких источников программно или когда группировка — лишь один из шагов сложной обработки.

Типичные ошибки
01
Вызов Свернуть() без второго параметра — все неперечисленные колонки удаляются из таблицы без возможности восстановления.
02
Использование РАЗЛИЧНЫЕ с лишними полями в выборке — уникальность считается по всей комбинации, и «дубли» остаются.
03
Суммирование после соединения один-ко-многим без предварительной группировки — итоги задваиваются или завышаются кратно числу связанных записей.
04
Попытка убрать дубли сортировкой или обходом выборки с проверкой «уже видели» — медленнее и сложнее штатных механизмов.

Дубли в СКД и динамических списках

В отчётах на системе компоновки данных повторяющиеся строки обычно означают, что группировки настроены не под структуру запроса. Если запрос возвращает детальные записи, а отчёт должен показывать сводные данные, добавьте в настройках СКД группировку по нужному измерению и уберите детальные записи из выборки. Ресурсы (суммы, количества) при этом должны быть указаны на закладке «Ресурсы» с корректной агрегатной функцией.

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

Отдельный случай — итоги по иерархии в СКД. Если строки верхнего уровня визуально «дублируют» данные нижних уровней, это не дубли, а итоги. Убрать их можно настройкой типа итогов группировки, не трогая запрос.

Маршрут решения

Как выбрать действие

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

Проверка результата и производительность

После устранения дублей результат нужно проверить. Минимальный контроль — сравнить количество строк до и после, а также сверить итоговые суммы с источником: они не должны измениться, если дубли были «техническими», и должны измениться предсказуемо, если строки агрегировались. Для отчётов полезно вывести рядом старый и новый вариант и сопоставить цифры по нескольким контрольным позициям.

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

Контрольные точки

Как проверить результат

Количество строк в результате
Норма

Совпадает с числом уникальных комбинаций ключевых полей

Тревожный признак

Строк больше, чем уникальных значений — дубли остались

Итоговые суммы
Норма

Суммы совпадают с контрольными данными источника

Тревожный признак

Суммы завышены кратно — строки размножаются соединением до агрегации

Состав полей выборки
Норма

Выбираются только поля, определяющие уникальность, плюс агрегаты

Тревожный признак

В выборке есть лишние поля, «ломающие» уникальность

Время выполнения запроса
Норма

Запрос выполняется за приемлемое время на рабочем объёме данных

Тревожный признак

Резкое замедление после добавления РАЗЛИЧНЫЕ — стоит пересмотреть структуру запроса

Порядок действий при типовой задаче

Соберём описанное в единый алгоритм для самой частой ситуации: запрос возвращает повторяющиеся строки, и нужно получить чистый результат без искажения данных.

Порядок действий
  1. 1
    Определите источник дублей: повторы в самой таблице или размножение строк соединением. Для этого временно выведите ключевые поля и посчитайте строки.
  2. 2
    Решите, что должно остаться: уникальный список значений или агрегированные данные с суммами и количествами.
  3. 3
    Для уникального списка добавьте РАЗЛИЧНЫЕ и уберите из выборки все поля, не определяющие уникальность.
  4. 4
    Для агрегатов замените РАЗЛИЧНЫЕ на СГРУППИРОВАТЬ ПО и оберните числовые поля в СУММА, МАКСИМУМ или КОЛИЧЕСТВО.
  5. 5
    Если дубли от соединения — вынесите детальную таблицу во вложенный запрос с группировкой по ключу связи.
  6. 6
    Проверьте результат: количество строк, итоговые суммы и отсутствие потерянных данных.
  7. 7
    Оцените время выполнения на реальном объёме и при необходимости перенесите отборы в условие ГДЕ до агрегации.

Если ни один из шагов не даёт результата, почти всегда причина в том, что «дубли» на самом деле различаются по какому-то незаметному полю — например, по скрытому полю периода или регистратора. Временно выведите все поля строки и найдите различие: после этого станет ясно, группировать по нему или исключить из выборки.

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

Часто задаваемые вопросы

Чем РАЗЛИЧНЫЕ отличается от СГРУППИРОВАТЬ ПО в запросе 1С?

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

Почему РАЗЛИЧНЫЕ не убирает дубли, хотя значения выглядят одинаково?

Строки считаются дублями только при совпадении всех выбранных полей. Чаще всего есть скрытое различие: другое значение поля периода, ссылочного поля или представления. Выведите все поля строки и сравните их попарно — различие найдётся. Также проверьте, не отличаются ли значения по типу, например строка и число с одинаковым отображением.

Как посчитать количество уникальных значений в запросе?

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

Можно ли убрать дубли уже в готовом отчёте на СКД, не меняя запрос?

Частично. Если дубли вызваны детальными записями, можно добавить группировку в настройках отчёта и убрать детальные строки. Но если повторы рождаются соединением в самом запросе, настройки СКД их не устранят корректно — итоги всё равно могут быть задвоены. Надёжнее исправить текст запроса в схеме компоновки.

Что делает метод Свернуть() и когда его применять вместо запроса?

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

Влияет ли РАЗЛИЧНЫЕ на скорость выполнения запроса?

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

Итог

Что важно запомнить

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