Потребовалось проверить таблицу значений на наличие дублей строк.
Поначалу, как обычно, в каждом отдельном случае писалась своя функция. Но вот это надоело, и была сделана попытка создать универсальную функцию, помещенную в общий модуль, которая по переданной ей таблице значений, наименованию или списку колонок проверяет наличие дублирующих строк.
В случае, если параметр «КонтролируемаяКолонка» не передан, проверка осуществляется по всем колонкам.
Так же имеется параметр, позволяющий исключить колонку «НомерСтроки» из проверки — подразумевается использование при создании проверяемой таблицы значений на основе табличной части.
Собственно, код ниже.
Буду рад комментариям.
// функция проверяет дубли строк таблицы значений по контролируемым колонкам
// Параметры:
// ТабЧасть — таблица значений
// КонтролируемаяКолонка — строка, списокЗначений — Наименование колонок;
// ТекстВозврата — переменная, куда будет возвращено значение
// УдалятьНомерСтроки — не учитывать колонку НомерСтроки, в случае, если не передан список колонок.
// Возвращаемые значения:
// в случае отсутствия дублей — ложь
// в случае наличия дублей — истина и в параметр «ТекстВозврата» записывается строковое значение дублей
Функция ПроверкаДублей(ТабЧасть, КонтролируемаяКолонка = Неопределено, ТекстВозврата = «», УдалятьНомерСтроки = Истина) Экспорт
ЕстьДубли = Ложь;
Если ТипЗнч(ТабЧасть) = Тип(«ТаблицаЗначений») тогда
Если ТипЗнч(КонтролируемаяКолонка) = Тип(«Строка») тогда
СтрокаСвертки = СокрЛП(КонтролируемаяКолонка);
ИначеЕсли ТипЗнч(КонтролируемаяКолонка) = Тип(«СписокЗначений») тогда
СтрокаСвертки = «»;
Для индекс = 0 по КонтролируемаяКолонка.Количество()-1 Цикл
Если Индекс > 0 тогда
СтрокаСвертки = СтрокаСвертки + «, «;
КонецЕсли;
СтрокаСвертки = СтрокаСвертки + СокрЛП(КонтролируемаяКолонка[Индекс]);
КонецЦикла;
Иначе
// проверяем на полные дубли
СтрокаСвертки = «»;
ПерваяКолонка = Истина;
Для индекс = 0 по ТабЧасть.Колонки.Количество()-1 Цикл
Если УдалятьНомерСтроки и СокрЛП(ТабЧасть.Колонки[Индекс].Имя) = «НомерСтроки» тогда
Продолжить;
КонецЕсли;
Если не ПерваяКолонка тогда
СтрокаСвертки = СтрокаСвертки + «, «;
КонецЕсли;
СтрокаСвертки = СтрокаСвертки + СокрЛП(ТабЧасть.Колонки[Индекс].Имя);
ПерваяКолонка = Ложь;
КонецЦикла;
КонецЕсли;
тз = ТабЧасть.Скопировать();
тз.Колонки.Добавить(«_КолонкаЕдиницы», Новый ОписаниеТипов(Новый КвалификаторыЧисла(1, 0, ДопустимыйЗнак.Неотрицательный)));
тз.ЗаполнитьЗначения(1,«_КолонкаЕдиницы»);
тз.Свернуть(СтрокаСвертки, «_КолонкаЕдиницы»);
для каждого стр из тз цикл
Если стр._КолонкаЕдиницы > 1 Тогда
ТекстВозврата = ТекстВозврата + «Дублирование строк: «;
ЕстьДубли = Истина;
Для ИндексКол = 0 по тз.колонки.Количество() — 1 цикл
Если тз.колонки[ИндексКол].Имя = «_КолонкаЕдиницы» тогда
ТекстВозврата = ТекстВозврата + » — найдено «+стр._КолонкаЕдиницы+» стр.»+Символы.ПС;
Иначе
Если ИндексКол > 0 тогда
ТекстВозврата = ТекстВозврата + «; «;
КонецЕсли;
ТекстВозврата = ТекстВозврата + Строка(стр[ИндексКол]);
КонецЕсли;
Конеццикла;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Возврат ЕстьДубли;
КонецФункции
Было бы неплохо выдавать в результате список строк с дублями. Примерно как выдает функция НайтиСтроки(). Потом проверка резульаьта на пустоту, и если он пустой, значит дублей нет. А так идея, на мой взгляд, правильная.
Спасибо. 🙂
На самом деле он формирует строки дублей, но в строке.
Можно переделать, что-бы возвращался список строк. немного усложнить алгоритм.
в блоке, где идет формирование строки для вывода добавить формирование отбора
Показать
А может стоит сделать запрос по таблице с группировкой по всем колонкам и суммой количества?
Таким образом получив значения строк дублей?
Можно. только тогда надо описывать все типы в таблице 🙁 пробовал запросом — с разбегу у меня не получилось…
типа
Выбрать * ИЗ тз
поместить ВременнаяТаблица
из &Таблица как тз
и из нее потом группировать?
там тогда запрос лучше ручками генерить. 🙁 долго — я помучался с этим и бросил — решил на циклах сделать 🙂
… просто выянить наличие дублей можно оценив изменение количества строк ТЗ после сворачивания.
(5) — шикарное решение.
если нужна просто проверка на наличие факта дублей без расшифровки — сама то!
тогда просто выкидываем циклы проверки и сразу проверяем количество строк исходной и свернутой!
(5) mxm2,
Добавлю:
Обычно ТЗ — это результат запроса.
Я в запросе вставляю строку примерно такую:
«1 КАК КоличествоДублей»
Затем сворачиваю копию ТЗ с суммированием по «КоличествоДублей» — получаю количество дублей по каждой позиции…
(7) AnryMc, в запросе — вообще просто, достаточно использовать группировки с суммированим Вашего поля Сумма(КоличествоДублей), даже сворачивать после не нужно
Если условия использования функции таковы, что в большинстве случаев дублей строк нет, то целесообразно было бы вставить в самое начало функции фрагмент кода:
ТЗ1 = Новый ТаблицаЗначений;
ТЗ1 = ТабЧасть.Выгрузить();
ТЗ1.Свернуть(КонтролируемаяКолонка, «»);
Если ТЗ1.Количество() = ТабЧасть.Количество() Тогда
Возврат Ложь;
КонецЕсли;
(9) Да. но тогда у нас только информация о наличии дублей, а о том, что именно задублировалось — нет.
так-то не очень гуманно пользователю сообщать — у тебя дубли — ищи сам, где 🙂
(8) mxm2,
Если запросом по табличной части документа, то дубли не найдёт т.к. будет присутствовать колонка «НомерСтроки»
(11) dr.death, если цель — определить наличие дублей, зачем запрашивать номер строки? Или, если нужен номер группировать с Максимум(НомерСтроки)
(12) mxm2,
Выбрать * по ТЧ вернёт все поля в т.ч. «НомерСтроки», ведь мы же говорим о универсальность, т.е. заранее не описаваем поля, которые хотим получить.
(13) На сколько я понял, в таком случае, если в таблице у поля есть составной тип — то его нужно описывать. Иначе запрос ругается на неизвестный тип. из-за этого и было сделано на циклах, а не на запросе — я не смог это победить. а обходить в цикле все колонки и проверять — лень 🙂
(14)
Я имел ввиду, что если в ТЧ заранее неизвестен состав колонок, то не получить написать запрос вида:
Вместо этого запроса можно написать Выбрать *, но тогда не получится выполнить функцию МАКСИМУМ.
Хотя есть вариант построить запрос в цикле
Показать
Сделал на основе вот этогоhttps://infostart.ru/public/95921/ по возможности универсально:
Показать