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

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

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

Способ 1. Внутреннее соединение таблицы самой с собой (Self-join)

Самый очевидный способ, который часто первым приходит в голову — это соединить таблицу документов с самой собой по тем реквизитам, которые должны совпадать. Рассмотрим этот метод на примере документа РеализацияТоваровУслуг. Предположим, нам нужно найти документы, у которых совпадают ДоговорКонтрагента, Реквизит1 и Реквизит2, но при этом это разные физические документы (у них разные номера или ссылки).

Разберем пример кода, предложенный в обсуждении:


ВЫБРАТЬ
    Реализация1.Ссылка КАК Документ1,
    Реализация2.Ссылка КАК Документ2,
    Реализация1.ДоговорКонтрагента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация2
        ПО Реализация1.ДоговорКонтрагента = Реализация2.ДоговорКонтрагента
            И Реализация1.Реквизит1 = Реализация2.Реквизит1
            И Реализация1.Реквизит2 = Реализация2.Реквизит2
            И Реализация1.Ссылка <> Реализация2.Ссылка

Проанализируем этот запрос:

  1. Мы выбираем таблицу Документ.РеализацияТоваровУслуг дважды, присваивая ей разные псевдонимы (Реализация1 и Реализация2).
  2. Используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Это означает, что в результат попадут только те записи, для которых нашлась пара по указанным условиям.
  3. В секции ПО мы перечисляем реквизиты, по которым ищем совпадения.
  4. Условие Реализация1.Ссылка <> Реализация2.Ссылка критически важно. Без него система сопоставит каждый документ сам с собой (ведь у документа А те же реквизиты, что и у документа А), и мы получим список всех документов в базе.

Важное дополнение: Исключение зеркальных дублей

При использовании условия Реализация1.Ссылка <> Реализация2.Ссылка мы столкнемся с проблемой "зеркальности". Если в базе есть два одинаковых документа (Док №1 и Док №2), запрос выдаст две строки:

  1. Док №1 — Док №2
  2. Док №2 — Док №1

Чтобы избежать этого и получить каждую пару только один раз, заменим условие неравенства на условие сравнения: Реализация1.Ссылка > Реализация2.Ссылка. Таким образом, в результат попадет только одна комбинация из пары.

Способ 2. Оптимизированный поиск через временные таблицы

Метод прямого соединения (Self-join) отлично работает на небольших объемах данных. Однако, если в таблице десятки тысяч документов, такое соединение может выполняться крайне медленно (СУБД придется перебирать огромное количество комбинаций). Проанализируем более профессиональный подход — использование группировок и временных таблиц.

Разобьем задачу на два этапа:

  1. Найдем комбинации реквизитов, которые встречаются более одного раза.
  2. Выберем все документы, соответствующие этим комбинациям.

Рассмотрим реализацию этого алгоритма:


// Шаг 1: Находим ключи дублей
ВЫБРАТЬ
    Реализация.ДоговорКонтрагента КАК ДоговорКонтрагента,
    Реализация.Реквизит1 КАК Реквизит1,
    Реализация.Реквизит2 КАК Реквизит2
ПОМЕСТИТЬ ВТ_КлючиДублей
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
СГРУППИРОВАТЬ ПО
    Реализация.ДоговорКонтрагента,
    Реализация.Реквизит1,
    Реализация.Реквизит2
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(Реализация.Ссылка) > 1
;

// Шаг 2: Выбираем документы по найденным ключам
ВЫБРАТЬ
    Реализация.Ссылка,
    Реализация.ДоговорКонтрагента,
    Реализация.Реквизит1,
    Реализация.Реквизит2
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_КлючиДублей КАК Ключи
        ПО Реализация.ДоговорКонтрагента = Ключи.ДоговорКонтрагента
            И Реализация.Реквизит1 = Ключи.Реквизит1
            И Реализация.Реквизит2 = Ключи.Реквизит2
УПОРЯДОЧИТЬ ПО
    Реализация.ДоговорКонтрагента,
    Реализация.Реквизит1

Почему этот способ лучше?

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

Ограничения и технические нюансы

При составлении подобных запросов необходимо учитывать несколько важных технических моментов, специфичных для платформы 1С:

  1. Типы данных: В языке запросов 1С нельзя использовать поля неограниченной длины (строки неограниченной длины, ХранилищеЗначения) в секциях СГРУППИРОВАТЬ ПО, СОЕДИНЕНИЕ или УПОРЯДОЧИТЬ ПО. Если ваш Реквизит1 — это длинный текст, вам придется использовать функцию ПОДСТРОКА(Реквизит1, 1, 1000) для сравнения.
  2. Пустые значения: Помните, что с точки зрения запроса две пустые ссылки одного типа — это одинаковые значения. Если у вас в 50 документах не заполнен ДоговорКонтрагента, запрос посчитает их дублями. Если это нежелательно, добавьте условие ГДЕ ДоговорКонтрагента <> ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка).
  3. Индексация: Для быстрого выполнения запроса реквизиты, по которым происходит поиск (Договор, Реквизит1 и т.д.), должны быть индексированы. В конфигураторе проверьте свойство "Индексировать" у соответствующих реквизитов документа.

Использование хеширования для большого количества полей

Если вам нужно сравнивать документы по 10 и более полям, текст запроса станет громоздким, а его выполнение — неэффективным. В таких случаях профессиональным решением будет добавление в документ скрытого реквизита ХешСумма (тип Строка, длина 32-64). При записи документа программно вычисляйте хеш (например, через Криптография.СформироватьХеш или просто конкатенацией строк) и записывайте его в это поле. Тогда поиск дублей сведется к простейшему запросу по одному индексированному полю ХешСумма.

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

← На главную