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

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

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

Метод 1: Использование метода Свернуть() с вспомогательной колонкой

Это классический и наиболее часто рекомендуемый способ. Его суть заключается в создании временной копии таблицы, добавлении колонки-счетчика и последующей группировке. Давайте разберем этот процесс по шагам.

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

  1. Выгружаем табличную часть в объект ТаблицаЗначений.
  2. Добавляем новую колонку (например, "Количество"), заполняем её единицей.
  3. Выполняем метод Свернуть(), указывая в группировках нужную колонку, а в суммируемых полях — нашу новую колонку.
  4. Анализируем результат: там, где число больше 1, был дубль.

Посмотрим на пример реализации в виде функции:


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

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

Метод 2: Поиск дублей через запрос

Использование механизмов запросов часто оказывается более производительным на больших объемах данных. Мы можем передать таблицу значений в запрос как параметр и использовать предложение СГРУППИРОВАТЬ ПО совместно с условием ИМЕЮЩИЕ.

Рассмотрим, как это выглядит в коде:


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

Запрос.УстановитьПараметр("ТЗ", Объект.Товары.Выгрузить());
Результат = Запрос.Выполнить();

Если Не Результат.Пустой() Тогда
    // Обработка найденных дублей
КонецЕсли;

Этот метод наиболее универсален, так как позволяет легко добавить проверку по нескольким полям сразу (например, Номенклатура + Характеристика), просто добавив их в секции ВЫБРАТЬ и СГРУППИРОВАТЬ ПО.

Метод 3: Оптимизированный поиск с использованием объекта "Соответствие"

Если задача стоит проверить наличие дублей максимально быстро "на лету" (например, при записи каждой строки), использование ТаблицаЗначений или Запроса может быть избыточным. Проанализируем альтернативный программный способ через объект Соответствие (хеш-таблица).

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


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

Этот способ выигрывает в скорости на средних объемах данных, так как не требует копирования всей таблицы в память для выполнения метода Выгрузить() и последующих трансформаций.

Метод 4: Использование индексации таблицы значений

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

Перед началом поиска по выгруженной таблице значений, выполним следующую команду:

Таблица.Индексы.Добавить("Номенклатура");

После этого вызовы НайтиСтроки() будут работать практически мгновенно, используя эффективно построенное дерево поиска.

Сравнение методов: что выбрать?

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

Проанализировав все варианты, мы видим, что универсального "самого лучшего" метода не существует, однако комбинация Свернуть() и проверки количества строк является золотым стандартом для большинства повседневных задач разработчика 1С.

← На главную