Разработка и Конфигурация · 11 мин
Как выбрать дубли в запросе 1С: практическое руководство
Как найти и выбрать дубли в запросе 1С: группировка с HAVING, соединение таблицы с самой собой, поиск дублей в справочниках и регистрах. Примеры кода и ошибки.
Дубли в данных 1С — типовая проблема: дважды заведённые контрагенты, повторяющиеся номенклатурные позиции, задвоенные записи в регистрах сведений. Прежде чем что-то удалять или объединять, дубли нужно корректно найти, и язык запросов 1С даёт для этого несколько рабочих инструментов: группировку с условием ИМЕЮЩИЕ (HAVING), соединение таблицы с самой собой и вложенные запросы.
Выбор способа зависит от задачи. Если нужно просто получить список значений, которые встречаются более одного раза, достаточно группировки с агрегатной функцией КОЛИЧЕСТВО. Если требуется вывести сами записи-дубли со всеми реквизитами — понадобится соединение результата группировки с исходной таблицей. Для поиска «похожих», но не идентичных значений (например, наименований с разным регистром букв) запрос придётся дополнить функциями обработки строк.
Ниже разобраны конкретные приёмы с готовыми текстами запросов, условия их применения, типичные ошибки и способы проверить, что запрос действительно нашёл дубли, а не вывалил лишнее.
Что считать дублем и какие поля брать в ключ
Прежде чем писать запрос, определите критерий дублирования. Для справочника «Контрагенты» дублем обычно считается совпадение ИНН и КПП, для «Номенклатуры» — совпадение наименования и артикула, для регистра сведений — совпадение измерений. От выбранного набора полей зависит, какие поля попадут в секцию СГРУППИРОВАТЬ ПО.
Важно понимать: ссылка элемента уникальна всегда, поэтому группировать по ссылке бессмысленно — дублей не будет никогда. Группировать нужно по «смысловым» реквизитам: ИНН, наименованию, номеру документа вместе с датой и организацией. Часто в ключ включают несколько полей сразу, чтобы отсечь случайные совпадения.
Базовый способ: СГРУППИРОВАТЬ ПО и ИМЕЮЩИЕ
Конструкция ИМЕЮЩИЕ — аналог HAVING в SQL. Она накладывает условие на результат группировки, то есть на агрегатные значения, а не на отдельные строки. Именно это отличает её от секции ГДЕ, которая фильтрует записи до группировки.
Пример: найти ИНН, которые встречаются у нескольких контрагентов.
ВЫБРАТЬ
Контрагенты.ИНН КАК ИНН,
КОЛИЧЕСТВО(Контрагенты.Ссылка) КАК КоличествоЗаписей
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.ИНН <> ""
И НЕ Контрагенты.ПометкаУдаления
СГРУППИРОВАТЬ ПО
Контрагенты.ИНН
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Контрагенты.Ссылка) > 1
Обратите внимание на фильтр в секции ГДЕ: пустые ИНН исключены, иначе все элементы с незаполненным ИНН схлопнутся в одну гигантскую «группу дублей». Помеченные на удаление элементы тоже разумно исключить, если задача — почистить актуальные данные.
Группировать можно по нескольким полям. Например, дубли документов по номеру, дате и контрагенту:
СГРУППИРОВАТЬ ПО
Реализация.Номер,
НАЧАЛОПЕРИОДА(Реализация.Дата, ДЕНЬ),
Реализация.Контрагент
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Как получить сами записи-дубли, а не только ключи
Группировка возвращает только ключ и количество. На практике чаще нужны сами элементы — чтобы вывести их в отчёт, пометить на удаление или передать в обработку объединения. Для этого результат группировки помещают во временную таблицу и соединяют с исходной таблицей.
ВЫБРАТЬ
Контрагенты.ИНН КАК ИНН
ПОМЕСТИТЬ ДублирующиесяИНН
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.ИНН <> ""
СГРУППИРОВАТЬ ПО
Контрагенты.ИНН
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
;
ВЫБРАТЬ
Контрагенты.Ссылка КАК Ссылка,
Контрагенты.Наименование КАК Наименование,
Контрагенты.ИНН КАК ИНН
ИЗ
Справочник.Контрагенты КАК Контрагенты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДублирующиесяИНН КАК Дубли
ПО Контрагенты.ИНН = Дубли.ИНН
УПОРЯДОЧИТЬ ПО
ИНН, Наименование
Внутреннее соединение оставит только те элементы, чей ИНН входит в список дублирующихся. Сортировка по ключу дубля группирует «пары» визуально — так результат удобнее проверять глазами.
- 1Определите ключевые поля, по которым считается дубль (ИНН, наименование и т.п.)
- 2Напишите запрос с СГРУППИРОВАТЬ ПО по ключевым полям и ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1
- 3Исключите пустые значения ключа и помеченные на удаление записи в секции ГДЕ
- 4Поместите ключи во временную таблицу и соедините с исходной таблицей, чтобы получить сами записи
- 5Проверьте результат на небольшой выборке вручную, прежде чем запускать обработку удаления
Альтернатива: соединение таблицы с самой собой
Второй классический приём — самосоединение (self join). Таблица соединяется сама с собой по ключевому полю, а условие на неравенство ссылок отсекает совпадение записи с самой собой.
ВЫБРАТЬ РАЗЛИЧНЫЕ
Т1.Ссылка КАК Ссылка,
Т1.ИНН КАК ИНН
ИЗ
Справочник.Контрагенты КАК Т1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Т2
ПО Т1.ИНН = Т2.ИНН
И Т1.Ссылка <> Т2.Ссылка
ГДЕ
Т1.ИНН <> ""
Без РАЗЛИЧНЫЕ каждая пара будет выведена дважды (А–Б и Б–А), а при трёх дублях — уже шесть строк. Этот способ нагляден, но на больших таблицах работает медленнее группировки: соединение порождает декартово произведение внутри каждой группы дублей.
Сравнение подходов
Быстрее на больших объёмах, сразу даёт счётчик дублей. Не возвращает сами записи — нужно соединение с исходной таблицей.
Сразу возвращает записи-дубли, удобно для попарного сравнения. Медленнее и требует РАЗЛИЧНЫЕ, иначе строки задваиваются.
Компактная запись без временных таблиц. На больших данных обычно уступает соединению с временной таблицей по скорости.
Поиск «похожих» значений и учёт регистра
Точное совпадение не находит дубли вида «ООО Ромашка» и «ООО Ромашка» (двойной пробел) или «ромашка» в другом регистре. Для таких случаев значения приводят к каноническому виду прямо в запросе: убирают лишние пробелы и приводят регистр функциями ВРЕГ или НРЕГ.
СГРУППИРОВАТЬ ПО
ВРЕГ(СОКРЛП(Контрагенты.Наименование))
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Учтите ограничение: СОКРЛП убирает пробелы только по краям строки, двойные пробелы внутри в запросе не схлопнуть — для этого потребуется предварительная обработка данных в коде. Если наименование — строка неограниченной длины, группировать по ней напрямую нельзя: сначала приведите её к ограниченной длине через ВЫРАЗИТЬ(... КАК СТРОКА(150)).
Дубли в регистрах сведений и накопления
В периодических регистрах сведений дубль — это несколько записей с одинаковым набором «период + измерения». Запрос строится по той же схеме: группировка по периоду и всем измерениям, условие ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1. Такие дубли часто появляются после нештатных загрузок или обменов.
В регистрах накопления задвоение обычно ищут по регистратору: один документ не должен делать две одинаковые записи с тем же номером строки. Если дубли возникли после обмена данными, проверьте, не дублируются ли сами регистраторы — чаще проблема именно в документах, а не в записях регистра.
Проверка результата и производительность
Перед тем как доверять запросу, выполните его в консоли запросов и сверьте несколько групп вручную: откройте найденные элементы и убедитесь, что они действительно дубли по вашему критерию. Полезный контроль — суммарное количество записей в выборке должно быть не меньше удвоенного количества групп дублей.
На больших таблицах (миллионы записей) группировка по неиндексированному реквизиту может выполняться долго. Ускорить помогает предварительное сужение выборки в секции ГДЕ: например, искать дубли только среди элементов, созданных за период загрузки, или только внутри одной папки справочника.
Как проверить результат
В каждой группе значения ключевых полей действительно совпадают
В одну группу попали записи с пустым ключом — забыт фильтр в ГДЕ
Равно сумме записей по всем группам дублей
Строк больше ожидаемого — вероятно, лишнее соединение размножило записи
Каждая ссылка встречается один раз
Ссылки задвоены — забыто ключевое слово РАЗЛИЧНЫЕ при самосоединении
Типичные ошибки при поиске дублей
Самая частая ошибка — условие на КОЛИЧЕСТВО помещают в секцию ГДЕ вместо ИМЕЮЩИЕ. Запрос либо не выполнится, либо вернёт некорректный результат, потому что ГДЕ работает до группировки и не видит агрегатов.
Вторая группа ошибок связана с данными: не исключены пустые значения ключа, из-за чего тысячи элементов без ИНН собираются в одну «группу дублей»; не учтён регистр букв и пробелы; в группировку включено поле, которое у разных дублей различается (например, дата создания), и реальные дубли разваливаются на отдельные группы.
Ответы на частые вопросы
Чем ИМЕЮЩИЕ отличается от ГДЕ в запросе 1С?
ГДЕ фильтрует строки до группировки и не может ссылаться на агрегатные функции. ИМЕЮЩИЕ применяется после группировки и работает с агрегатами — именно там пишется условие КОЛИЧЕСТВО(*) > 1 для поиска дублей.
Как найти дубли по наименованию без учёта регистра?
Сгруппируйте по выражению ВРЕГ(СОКРЛП(Наименование)) и добавьте ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1. Учтите, что СОКРЛП убирает пробелы только по краям строки; двойные пробелы внутри потребуют предварительной обработки данных.
Почему запрос с самосоединением выводит каждую пару дважды?
Потому что соединение находит обе комбинации: запись А с записью Б и запись Б с записью А. Добавьте РАЗЛИЧНЫЕ по ссылке или условие вида Т1.Ссылка < Т2.Ссылка, если нужны именно пары.
Можно ли группировать по полю с неограниченной длиной строки?
Нет, запрос завершится ошибкой. Сначала приведите поле к фиксированной длине: ВЫРАЗИТЬ(Поле КАК СТРОКА(150)) — и группируйте по этому выражению.
Как найти дубли записей в периодическом регистре сведений?
Сгруппируйте по периоду и всем измерениям регистра и отберите группы с ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1. Такие дубли чаще всего появляются после загрузок и обменов — проверьте источник данных.
Что быстрее: группировка или самосоединение?
На больших таблицах группировка с ИМЕЮЩИЕ и последующим соединением с исходной таблицей обычно быстрее, так как не порождает попарных комбинаций. Самосоединение удобнее для наглядного сравнения пар, но хуже масштабируется.
Что важно запомнить
Дубли в запросе 1С выбирают группировкой по ключевым полям с условием ИМЕЮЩИЕ КОЛИЧЕСТВО(*) > 1; сами записи получают соединением с результатом группировки. Обязательно исключайте пустые ключи, помните про регистр и длину строк, а любые действия по удалению выполняйте только после резервной копии и ручной проверки выборки.