ТаблицаЗначений. Проверка дублей.

07.11.13

Разработка - Универсальные функции

Функция проверки дублей строк по значениям некоторых колонок.

Потребовалось проверить таблицу значений на наличие дублей строк.

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

В случае, если параметр "КонтролируемаяКолонка" не передан, проверка осуществляется по всем колонкам.

Так же имеется параметр, позволяющий исключить колонку "НомерСтроки" из проверки - подразумевается использование при создании проверяемой таблицы значений на основе табличной части.

 

Собственно, код ниже.

Буду рад комментариям.

// функция проверяет дубли строк таблицы значений по контролируемым колонкам
// Параметры:
// ТабЧасть - таблица значений
// КонтролируемаяКолонка - строка, списокЗначений - Наименование колонок;
// ТекстВозврата - переменная, куда будет возвращено значение
// УдалятьНомерСтроки - не учитывать колонку НомерСтроки, в случае, если не передан список колонок.
// Возвращаемые значения:
// в случае отсутствия дублей - ложь
// в случае наличия дублей - истина и в параметр "ТекстВозврата" записывается строковое значение дублей

Функция ПроверкаДублей(ТабЧасть, КонтролируемаяКолонка = Неопределено, ТекстВозврата = "", УдалятьНомерСтроки = Истина) Экспорт

   
ЕстьДубли = Ложь;

    Если
ТипЗнч(ТабЧасть) = Тип("ТаблицаЗначений") тогда

        Если
ТипЗнч(КонтролируемаяКолонка) = Тип("Строка") тогда
           
СтрокаСвертки = СокрЛП(КонтролируемаяКолонка);
        ИначеЕсли
ТипЗнч(КонтролируемаяКолонка) = Тип("СписокЗначений") тогда
           
СтрокаСвертки = "";
            Для
индекс = 0 по КонтролируемаяКолонка.Количество()-1 Цикл
                Если
Индекс > 0 тогда
                   
СтрокаСвертки = СтрокаСвертки + ", ";
                КонецЕсли;
               
СтрокаСвертки = СтрокаСвертки + СокрЛП(КонтролируемаяКолонка[Индекс]);
            КонецЦикла;
        Иначе
           
// проверяем на полные дубли
           
СтрокаСвертки = "";
           
ПерваяКолонка = Истина;
            Для
индекс = 0 по ТабЧасть.Колонки.Количество()-1 Цикл
                Если
УдалятьНомерСтроки и СокрЛП(ТабЧасть.Колонки[Индекс].Имя) = "НомерСтроки" тогда
                    Продолжить;
                КонецЕсли;
                Если не
ПерваяКолонка тогда
                   
СтрокаСвертки = СтрокаСвертки + ", ";
                КонецЕсли;
               
СтрокаСвертки = СтрокаСвертки + СокрЛП(ТабЧасть.Колонки[Индекс].Имя);
               
ПерваяКолонка = Ложь;
            КонецЦикла;
        КонецЕсли;

       
тз = ТабЧасть.Скопировать();
       
тз.Колонки.Добавить("_КолонкаЕдиницы", Новый ОписаниеТипов(Новый КвалификаторыЧисла(1, 0, ДопустимыйЗнак.Неотрицательный)));
       
тз.ЗаполнитьЗначения(1,"_КолонкаЕдиницы");
       
тз.Свернуть(СтрокаСвертки, "_КолонкаЕдиницы");

        для каждого
стр из тз цикл
            Если
стр._КолонкаЕдиницы > 1 Тогда
               
ТекстВозврата = ТекстВозврата + "Дублирование строк: ";
               
ЕстьДубли = Истина;
                Для
ИндексКол = 0 по тз.колонки.Количество() - 1 цикл
                    Если
тз.колонки[ИндексКол].Имя = "_КолонкаЕдиницы" тогда
                       
ТекстВозврата = ТекстВозврата + " - найдено "+стр._КолонкаЕдиницы+" стр."+Символы.ПС;
                    Иначе
                        Если
ИндексКол > 0 тогда
                           
ТекстВозврата = ТекстВозврата + "; ";
                        КонецЕсли;
                       
ТекстВозврата = ТекстВозврата + Строка(стр[ИндексКол]);
                    КонецЕсли;
                Конеццикла;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;

    Возврат
ЕстьДубли;

КонецФункции

Проверка дублей ТаблицаЗначений

См. также

Печать любых непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать любые печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

3480 руб.

22.08.2023    786    1    0    

1

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    3021    YA_418728146    3    

84

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    13185    100    sapervodichka    106    

118

Система контроля ведения учета [БСП]

Универсальные функции Механизмы типовых конфигураций БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    6311    quazare    8    

103

Хитрости СКД. Часть 3

СКД Универсальные функции Платформа 1С v8.3 Система компоновки данных Конфигурации 1cv8 Бесплатно (free)

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

28.05.2022    7649    milkers    11    

87

Базовые принципы работы с регламентными заданиями подсистем БСП

Универсальные функции БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В очередной публикации рассмотрим некоторые базовые приемы работы с регламентными заданиями в рамках библиотеки стандартных подсистем

22.05.2022    12344    quazare    25    

57
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. 13jaguar 94 13.11.13 07:04 Сейчас в теме
Было бы неплохо выдавать в результате список строк с дублями. Примерно как выдает функция НайтиСтроки(). Потом проверка резульаьта на пустоту, и если он пустой, значит дублей нет. А так идея, на мой взгляд, правильная.
2. razin 40 13.11.13 07:59 Сейчас в теме
Спасибо. :)
На самом деле он формирует строки дублей, но в строке.
Можно переделать, что-бы возвращался список строк. немного усложнить алгоритм.
в блоке, где идет формирование строки для вывода добавить формирование отбора

для каждого стр из тз цикл
 Если стр._КолонкаЕдиницы > 1 Тогда
  ТекстВозврата = ТекстВозврата + "Дублирование строк: ";
  ЕстьДубли = Истина;
				
  // Создадим отбор
  Отбор = Новый Структура;
  //отбор
				
  Для ИндексКол = 0 по тз.колонки.Количество() - 1 цикл
     Если тз.колонки[ИндексКол].Имя = "_КолонкаЕдиницы" тогда
        ТекстВозврата = ТекстВозврата + " - найдено "+стр._КолонкаЕдиницы+" стр."+Символы.ПС;
     Иначе
	// добавим в структуру отбора значение этой колонки
	Отбор.Вставить(тз.колонки[ИндексКол].Имя, стр[ИндексКол]);
	// отбор
						
	Если ИндексКол > 0 тогда
          ТекстВозврата = ТекстВозврата + "; ";
        КонецЕсли;
        ТекстВозврата = ТекстВозврата + Строка(стр[ИндексКол]);
      КонецЕсли;
  Конеццикла;
			
// тут у нас есть структура отбора можем ее использовать для поиска строк в первоначальной таблице
       массивДублей = ТабЧасть.НайтиСтроки(Отбор);
// теперь в переменной массивДублей у нас лежат строки, соотретствующие задублированным ПО ОДНОМУ УСЛОВИЮ!!!
// дальше его можно или поместить в СписокЗначений или в ТаблицуЗначений, которую передать в параметре.
// Допустим, так:
// в параметры функции добавляем : "СписокСтрокДублей = Новый СписокЗначений"
// ну а тут :
// СписокСтрокДублей.Добавить(массивДублей, стр._КолонкаЕдиницы);
// тогда на выходе у нас будет список значений, в котором представление элемента списка - это количество 
// задублированных строк, а значение - массив СтрокТабличнойЧасти.
// Ну, как-то так... :)
			
 КонецЕсли;
КонецЦикла;
Показать
3. Kov495 11 13.11.13 09:21 Сейчас в теме
А может стоит сделать запрос по таблице с группировкой по всем колонкам и суммой количества?
Таким образом получив значения строк дублей?
4. razin 40 13.11.13 10:12 Сейчас в теме
Можно. только тогда надо описывать все типы в таблице :( пробовал запросом - с разбегу у меня не получилось...
типа

Выбрать * ИЗ тз
поместить ВременнаяТаблица
из &Таблица как тз

и из нее потом группировать?

там тогда запрос лучше ручками генерить. :( долго - я помучался с этим и бросил - решил на циклах сделать :)
5. mxm2 1248 13.11.13 10:20 Сейчас в теме
... просто выянить наличие дублей можно оценив изменение количества строк ТЗ после сворачивания.
levante90; fomix; razin; +3 Ответить
6. razin 40 13.11.13 10:48 Сейчас в теме
(5) - шикарное решение.
если нужна просто проверка на наличие факта дублей без расшифровки - сама то!
тогда просто выкидываем циклы проверки и сразу проверяем количество строк исходной и свернутой!
7. AnryMc 846 13.11.13 11:01 Сейчас в теме
(5) mxm2,

Добавлю:

Обычно ТЗ - это результат запроса.

Я в запросе вставляю строку примерно такую:

"1 КАК КоличествоДублей"

Затем сворачиваю копию ТЗ с суммированием по "КоличествоДублей" - получаю количество дублей по каждой позиции...
8. mxm2 1248 13.11.13 11:21 Сейчас в теме
(7) AnryMc, в запросе - вообще просто, достаточно использовать группировки с суммированим Вашего поля Сумма(КоличествоДублей), даже сворачивать после не нужно
11. 1cprogr_nsk 105 14.11.13 11:20 Сейчас в теме
(8) mxm2,
Если запросом по табличной части документа, то дубли не найдёт т.к. будет присутствовать колонка "НомерСтроки"
12. mxm2 1248 14.11.13 11:32 Сейчас в теме
(11) dr.death, если цель - определить наличие дублей, зачем запрашивать номер строки? Или, если нужен номер группировать с Максимум(НомерСтроки)
13. 1cprogr_nsk 105 14.11.13 11:53 Сейчас в теме
(12) mxm2,
Выбрать * по ТЧ вернёт все поля в т.ч. "НомерСтроки", ведь мы же говорим о универсальность, т.е. заранее не описаваем поля, которые хотим получить.
14. razin 40 14.11.13 12:52 Сейчас в теме
(13) На сколько я понял, в таком случае, если в таблице у поля есть составной тип - то его нужно описывать. Иначе запрос ругается на неизвестный тип. из-за этого и было сделано на циклах, а не на запросе - я не смог это победить. а обходить в цикле все колонки и проверять - лень :)
15. 1cprogr_nsk 105 14.11.13 13:16 Сейчас в теме
(14)
Я имел ввиду, что если в ТЧ заранее неизвестен состав колонок, то не получить написать запрос вида:
ВЫБРАТЬ
   МАКСИМУМ(НомерСтроки) КАК НенужноеПоле,
   1 КАК КоличествоДублей,
   ПолеТЧ1, КАК Поле1,
   ПолеТЧ2, КАК Поле2,
   ...
   ПолеТЧN КАК ПолеN

Вместо этого запроса можно написать Выбрать *, но тогда не получится выполнить функцию МАКСИМУМ.

Хотя есть вариант построить запрос в цикле
 //Проверяем, если ТИП табличная часть документа тогда
ТекстЗапроса = "Выбрать" + Символы.ПС;
Для каждого КолонкаТЧ Из ТабличнаяЧасть.Колонки Цикл
    ТекстЗапроса = ТекстЗапроса + ?(КолонкаТЧ.Имя = "НомерСтроки", "МАКСИМУМ("+КолонкаТЧ.Имя+") КАК   максСтрок,", КолонкаТЧ.Имя + " КАК " + КолонкаТЧ.Имя) + Символы.ПС;
КонецЦикла;
ТекстЗапроса = ТекстЗапроса + "1 КАК КоличествоДублей" + Символы.ПС + "ИЗ &ТаблицаЗначений";
9. torch 126 13.11.13 17:25 Сейчас в теме
Если условия использования функции таковы, что в большинстве случаев дублей строк нет, то целесообразно было бы вставить в самое начало функции фрагмент кода:

ТЗ1 = Новый ТаблицаЗначений;
ТЗ1 = ТабЧасть.Выгрузить();
ТЗ1.Свернуть(КонтролируемаяКолонка, "");
Если ТЗ1.Количество() = ТабЧасть.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Прикрепленные файлы:
10. razin 40 14.11.13 08:31 Сейчас в теме
(9) Да. но тогда у нас только информация о наличии дублей, а о том, что именно задублировалось - нет.
так-то не очень гуманно пользователю сообщать - у тебя дубли - ищи сам, где :)
16. ProProProProPro 17.08.15 14:07 Сейчас в теме
ТЗДубли = Новый ТаблицаЗначений;
	ТЗДубли.Колонки.Добавить("Артикул");
		
	Для Каждого СтрокаАртикул ИЗ ТЗОтгрузка Цикл
		Отбор = Новый Структура;
		Отбор.Вставить("Артикул", СтрокаАртикул.Артикул);
		Строки = ТЗОтгрузка.НайтиСтроки(Отбор);
		Если Строки.Количество() > 1 Тогда
			Если ТЗДубли.Найти(СтрокаАртикул.Артикул) = Неопределено Тогда
				Для Каждого Стр ИЗ Строки Цикл
					СтрокаТЗДубли = ТЗДубли.Добавить();
					СтрокаТЗДубли.Артикул = Стр.Артикул;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ТЗДубли.Количество() > 0 Тогда
	         Возврат ТЗДубли
        КонецЕсли;
Показать
baracuda; +1 Ответить
17. brylig 17.10.18 08:52 Сейчас в теме
Сделал на основе вот этого https://infostart.ru/public/95921/ по возможности универсально:

&НаКлиенте
Процедура НайтиДубли(Команда)
	Поля = Новый Массив;
	Поля.Добавить("Номенклатура");
	Поля.Добавить("Характеристика");
	Дубли = ПроверитьТЧНаДубли(Объект.ТЧ, Поля);
	Если Дубли.Количество() > 0 Тогда
		Для Каждого Дубль Из Дубли Цикл
			Сообщить("Табличная часть имеет дубли в строках №:");
			Для Каждого СтрокаДубля Из Дубль Цикл
				Сообщить(СтрокаДубля);
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПроверитьТЧНаДубли(Знач ТЧ, Поля) Экспорт
	Возврат ПроверитьТЗНаДубли(ТЧ.Выгрузить(), Поля);
КонецФункции

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