Было бы неплохо выдавать в результате список строк с дублями. Примерно как выдает функция НайтиСтроки(). Потом проверка резульаьта на пустоту, и если он пустой, значит дублей нет. А так идея, на мой взгляд, правильная.
Спасибо. :)
На самом деле он формирует строки дублей, но в строке.
Можно переделать, что-бы возвращался список строк. немного усложнить алгоритм.
в блоке, где идет формирование строки для вывода добавить формирование отбора
для каждого стр из тз цикл
Если стр._КолонкаЕдиницы > 1 Тогда
ТекстВозврата = ТекстВозврата + "Дублирование строк: ";
ЕстьДубли = Истина;
// Создадим отборОтбор = Новый Структура;//отбор
Для ИндексКол = 0 по тз.колонки.Количество() - 1 цикл
Если тз.колонки[ИндексКол].Имя = "_КолонкаЕдиницы" тогда
ТекстВозврата = ТекстВозврата + " - найдено "+стр._КолонкаЕдиницы+" стр."+Символы.ПС;
Иначе
// добавим в структуру отбора значение этой колонкиОтбор.Вставить(тз.колонки[ИндексКол].Имя, стр[ИндексКол]);// отбор
Если ИндексКол > 0 тогда
ТекстВозврата = ТекстВозврата + "; ";
КонецЕсли;
ТекстВозврата = ТекстВозврата + Строка(стр[ИндексКол]);
КонецЕсли;
Конеццикла;
// тут у нас есть структура отбора можем ее использовать для поиска строк в первоначальной таблицемассивДублей = ТабЧасть.НайтиСтроки(Отбор);// теперь в переменной массивДублей у нас лежат строки, соотретствующие задублированным ПО ОДНОМУ УСЛОВИЮ!!!
// дальше его можно или поместить в СписокЗначений или в ТаблицуЗначений, которую передать в параметре.
// Допустим, так:
// в параметры функции добавляем : "СписокСтрокДублей = Новый СписокЗначений"
// ну а тут :
// СписокСтрокДублей.Добавить(массивДублей, стр._КолонкаЕдиницы);
// тогда на выходе у нас будет список значений, в котором представление элемента списка - это количество
// задублированных строк, а значение - массив СтрокТабличнойЧасти.
// Ну, как-то так... :)
КонецЕсли;
КонецЦикла;
(5) - шикарное решение.
если нужна просто проверка на наличие факта дублей без расшифровки - сама то!
тогда просто выкидываем циклы проверки и сразу проверяем количество строк исходной и свернутой!
(7) AnryMc, в запросе - вообще просто, достаточно использовать группировки с суммированим Вашего поля Сумма(КоличествоДублей), даже сворачивать после не нужно
(12) mxm2,
Выбрать * по ТЧ вернёт все поля в т.ч. "НомерСтроки", ведь мы же говорим о универсальность, т.е. заранее не описаваем поля, которые хотим получить.
(13) На сколько я понял, в таком случае, если в таблице у поля есть составной тип - то его нужно описывать. Иначе запрос ругается на неизвестный тип. из-за этого и было сделано на циклах, а не на запросе - я не смог это победить. а обходить в цикле все колонки и проверять - лень :)
(14)
Я имел ввиду, что если в ТЧ заранее неизвестен состав колонок, то не получить написать запрос вида:
ВЫБРАТЬ
МАКСИМУМ(НомерСтроки) КАК НенужноеПоле,
1 КАК КоличествоДублей,
ПолеТЧ1, КАК Поле1,
ПолеТЧ2, КАК Поле2,
...
ПолеТЧN КАК ПолеN
Вместо этого запроса можно написать Выбрать *, но тогда не получится выполнить функцию МАКСИМУМ.
Хотя есть вариант построить запрос в цикле
//Проверяем, если ТИП табличная часть документа тогда
ТекстЗапроса = "Выбрать" + Символы.ПС;
Для каждого КолонкаТЧ Из ТабличнаяЧасть.Колонки Цикл
ТекстЗапроса = ТекстЗапроса + ?(КолонкаТЧ.Имя = "НомерСтроки", "МАКСИМУМ("+КолонкаТЧ.Имя+") КАК максСтрок,", КолонкаТЧ.Имя + " КАК " + КолонкаТЧ.Имя) + Символы.ПС;
КонецЦикла;
ТекстЗапроса = ТекстЗапроса + "1 КАК КоличествоДублей" + Символы.ПС + "ИЗ &ТаблицаЗначений";
Если условия использования функции таковы, что в большинстве случаев дублей строк нет, то целесообразно было бы вставить в самое начало функции фрагмент кода:
ТЗ1 = Новый ТаблицаЗначений;
ТЗ1 = ТабЧасть.Выгрузить();
ТЗ1.Свернуть(КонтролируемаяКолонка, "");
Если ТЗ1.Количество() = ТабЧасть.Количество() Тогда
Возврат Ложь;
КонецЕсли;
(9) Да. но тогда у нас только информация о наличии дублей, а о том, что именно задублировалось - нет.
так-то не очень гуманно пользователю сообщать - у тебя дубли - ищи сам, где :)
ТЗДубли = Новый ТаблицаЗначений;
ТЗДубли.Колонки.Добавить("Артикул");
Для Каждого СтрокаАртикул ИЗ ТЗОтгрузка Цикл
Отбор = Новый Структура;
Отбор.Вставить("Артикул", СтрокаАртикул.Артикул);
Строки = ТЗОтгрузка.НайтиСтроки(Отбор);
Если Строки.Количество() > 1 Тогда
Если ТЗДубли.Найти(СтрокаАртикул.Артикул) = Неопределено Тогда
Для Каждого Стр ИЗ Строки Цикл
СтрокаТЗДубли = ТЗДубли.Добавить();
СтрокаТЗДубли.Артикул = Стр.Артикул;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ТЗДубли.Количество() > 0 Тогда
Возврат ТЗДубли
КонецЕсли;
&НаКлиенте
Процедура НайтиДубли(Команда)
Поля = Новый Массив;
Поля.Добавить("Номенклатура");
Поля.Добавить("Характеристика");
Дубли = ПроверитьТЧНаДубли(Объект.ТЧ, Поля);
Если Дубли.Количество() > 0 Тогда
Для Каждого Дубль Из Дубли Цикл
Сообщить("Табличная часть имеет дубли в строках №:");
Для Каждого СтрокаДубля Из Дубль Цикл
Сообщить(СтрокаДубля);
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьТЧНаДубли(Знач ТЧ, Поля) Экспорт
Возврат ПроверитьТЗНаДубли(ТЧ.Выгрузить(), Поля);
КонецФункции
&НаСервереБезКонтекста
//Функция поиска дублей в таблицах значений.
//Получает:
//ТЗ - таблицу значений (должна иметь стандартную колонку с уникальным индексом "НомерСтроки");
//Поля - массив полей для отбора (если нет, то используются все поля таблицы, кроме "НомерСтроки" и "ИсходныйНомерСтроки").
//Возвращает:
//Массив Дубли массивов Дубль, содержащих НомерСтроки дублированных записей.
Функция ПроверитьТЗНаДубли(ТЗ, Поля) Экспорт
Если ТипЗнч(ТЗ) <> Тип("ТаблицаЗначений") Тогда
Возврат Неопределено;
Иначе
Отбор = Новый Структура();
Дубли = Новый Массив;
Если Поля.Количество() = 0 ИЛИ Поля = Неопределено Тогда
Для Каждого Поле Из ТЗ.Колонки Цикл
Если Поле.Имя <> "НомерСтроки" И Поле.Имя <> "ИсходныйНомерСтроки" Тогда Поля.Добавить(Поле.Имя); КонецЕсли;
КонецЦикла;
КонецЕсли;
Пока ТЗ.Количество() > 0 Цикл
СтрокаТЗ = ТЗ[0];
Отбор.Очистить();
Для Каждого Поле Из Поля Цикл
КолонкаТЗ = ТЗ.Колонки.Найти(Поле);
Если НЕ КолонкаТЗ = Неопределено Тогда Отбор.Вставить(Поле, СтрокаТЗ[Поле]); КонецЕсли;
КонецЦикла;
СтрокиДубля = ТЗ.НайтиСтроки(Отбор);
Если СтрокиДубля.Количество() > 1 Тогда
Дубль = Новый Массив;
Для Каждого СтрокаДубля Из СтрокиДубля Цикл
Дубль.Добавить(СтрокаДубля.НомерСтроки);
ТЗ.Удалить(СтрокаДубля);
КонецЦикла;
Дубли.Добавить(Дубль);
Иначе
ТЗ.Удалить(СтрокиДубля[0]);
КонецЕсли;
КонецЦикла;
Возврат Дубли;
КонецЕсли;
КонецФункции