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