Проверка на наличие дублирующихся строк в табличных частях

04.04.18

Разработка - Запросы

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

Скачать файлы

Наименование Файл Версия Размер
Проверка на наличие дублирующихся строк в табличных частях
.epf 17,41Kb
9
.epf 1 17,41Kb 9 Скачать

Думаю, каждый программист рано или поздно сталкивался с подобной задачей: как реализовать проверку на наличие дублирующихся строк в табличных частях. Кому-то просто нужно проверить: есть, или нет, дубли. Кому-то нужно известить пользователя, и сообщить ему номера строк с дублями. Это вопросы будут рассмотрены в данной статье. Но давайте сразу определимся с терминологией: поля, по которым будет осуществляться контроль, назовем «ключевые».

Итак, предположим, что у нас стоит задача проверить наличие дублей строк табличной части по ключевым полям. Пусть это будет документ «Реализация товаров, услуг», дубли строк мы будем искать в табличной части «Товары», а в качестве ключевых полей будем использовать следующие реквизиты табличной части: Качество, Номенклатура, Склад, СерияНоменклатуры и ХарактеристикаНоменклатуры.

Рассмотрим следующие ситуации:

1) Проверка на наличие дублирующихся строк на уровне есть/нет. Реализация ее будет выглядеть следующим образом:

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

Здесь все достаточно просто. Обращаемся к данным табличной части документа, группируем по ключевым полям с использование агрегатной функции для подсчета количества номеров строк. Накладываем условие по вычисленному значению агрегатной функции. Все.

2) Классика жанра. Выведем в сообщении пользователю номера всех тех строк табличной части, которые являются дублями.

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

Здесь все тоже не слишком сложно. Обратились к данным табличной части документа, поместили их во временную таблицу. Далее работаем со временной таблицей. Обращаемся к ней, отбираем те данные, по которым есть дубли (условие с использованием вложенного запроса). А далее, для того, чтобы сохранить все множество значений номеров строк, нам необходимо по ключевым полям объявить итоги. В таком случае в результате запроса, при использовании механизма итогов, появляются дополнительные строки, в которых хранится итог для того, или иного поля, а сам результат принимает иерархический вид, или вид дерева. Для того, чтобы вывести пользователю сообщение, нам нужно обойти результат запроса, и по каждому набору ключевых полей скомпоновать текст сообщения, и выдать его пользователю.

А теперь попробуем оценить перспективу доработки. Допустим, у нас изменился состав ключевых полей в сторону увеличения их количества: добавились ЕдиницаИзмерения и ЗаказПокупателя. Чтобы контроль дублей строк не перестал работать, нам нужно доработать запрос и обход результата запроса следующим образом:

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

3) Альтернативный вариант. Реализация предыдущего варианта другим способом. Предлагаю использовать особенность запросов 1С, позволяющих обращаться к данным табличных частей, как к обычным полям выборки. Ну все-таки не совсем обычным, но все же полям выборки. Кроме того, нам придётся использовать не самый оптимальный способ соединения данных - декартово произведение. Почему так - опишу ниже.

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

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

Несколько комментариев по поводу запроса.

Работа с табличными частями в качестве полей выборки накладывает ряд ограничений на выполнение запросов. Во-первых, это работа с временными таблицами. Т.е. нельзя помещать такие объекты во временные таблицы, но никто не мешает использовать вложенные запросы. Во-вторых, это соединения таблиц. Мне требовалось написать такой запрос, который бы возвратил мне наборы ключевых полей по которым имеются дубли, и многострочный объект, содержащий все строки с таким же набором ключевых полей. Обычные соединения (ВНУТРЕННЕЕ, ЛЕВОЕ, ПРАВОЕ, ПОЛНОЕ) возвращают всю табличную часть, что, в общем, правильно – для части объекта условие соединения же выполняется? Выполняется. Ну тогда и получите всю табличную часть. Искомый результат, как оказалось, достигается декартовым произведением. Мне как-то претит видеть в тексте запроса перечисление таблиц через запятую, поэтому я все декартовы произведения всегда реализую через «... СОЕДИНЕНИЕ ... ПО (ИСТИНА)». Чтобы ограничить мсье Декарта в аппетитах (и повысить производительность), применяются дополнительные ограничения.

Теперь о производительности. Производились тестовые замеры каждого из вариантов на документе с большим количеством строк в табличной части. Количество строк в тестируемом документе: 47 817, 4 комбинации ключевых полей с дублями по 2, 2, 3 и 4 строки. Результаты замеров:

Вариант 1) 0:00:00.078 сек.

Вариант 2) 0:00:00.265 сек.

Вариант 3) 0:00:01.513 сек.

Как видим, третий вариант, как и ожидалось, самый медленный, но он же является самым удобным в перспективе модификации.

 

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

1) Выбираем вид объекта: Документ или Справочник.

2) Выбираем тип объекта: Какой именно документ или справочник.

3) Выбираем табличную часть объекта.

4) Определяем состав ключевых полей в специальном диалоге

5) Если мы хотим, то можем указать ссылку на объект, чтобы проверить его на наличие дублей.

6) Если активен флажок «Сгенерировать и показать код для проверки на дубли», то будет сгенерирован программный код для выполнения проверки на дубли строк с имеющимися настройками.

дубли дубли строк дублирующиеся строки

См. также

SALE! 20%

Infostart Toolkit: Инструменты разработчика 1С 8.3 на управляемых формах

Инструментарий разработчика Роли и права Запросы СКД Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

13000 10400 руб.

02.09.2020    122223    673    389    

715

Для чего используют конструкцию запроса "ГДЕ ЛОЖЬ" в СКД на примере конфигурации 1С:ERP

Запросы СКД Платформа 1С v8.3 Запросы Система компоновки данных 1С:ERP Управление предприятием 2 Бесплатно (free)

В типовых конфигурациях разработчики компании 1С иногда используют в отчетах, построенных на СКД, такую конструкцию, как "ГДЕ ЛОЖЬ". Такая конструкция говорит о том, что данные в запросе не будут получены совсем. Для чего же нужен тогда запрос?

13.02.2024    5750    KawaNoNeko    23    

23

Набор-объект для СКД по тексту или запросу

Запросы СКД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    2004    2    Yashazz    0    

29

Запрос 1С copilot

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

Пишем на человеческом языке, что нам надо, и получаем текст запроса на языке 1С. Используются большие языковые модели (LLM GPT) от OpenAI или Яндекс на выбор.

5 стартмани

15.01.2024    6293    31    mkalimulin    25    

50

PrintWizard: поддержка представлений ЗУП в конструкторе

Инструментарий разработчика Запросы Платформа 1С v8.3 Бесплатно (free)

Одной из интересных задач, стоящих в процессе разработки, была поддержка механизма представлений в ЗУП. Но не просто возможность исполнения запросов с ними. Основная проблема была в том, чтобы с ними было удобно работать, а именно: создавать, модифицировать и отлаживать. Кратко о том, что в итоге получилось...

14.12.2023    1742    vandalsvq    7    

29

Объектная модель запроса "Схема запроса" 2

Запросы Платформа 1С v8.3 Запросы Конфигурации 1cv8 Бесплатно (free)

Далеко уже не новый тип данных "Схема запроса". Статья о том, как использовать его "попроще". Примеры создания текста запроса с нуля и изменение имеющегося запроса.

06.12.2023    5391    user1923546    26    

43

Начните уже использовать хранилище запросов

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    16190    skovpin_sa    14    

98
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. klinval 337 09.04.18 15:05 Сейчас в теме
Выгружаешь в таблицы значений (например ЭтотОбъект.Товары.Выгрузить()) и сравниваешь любым методом из статьи Ильдаровича: https://infostart.ru/public/326983/
2. RotaninV 23 09.04.18 18:19 Сейчас в теме
(1) Тоже один из вариантов, имеющих право на жизнь. Выбирайте тот, который устраивает вас.
Мой вариант интересен в том числе как способ получения нужного набора строк табличной части в одном поле выборки.
Оставьте свое сообщение