Проверка на наличие дублирующихся строк в табличных частях
Время прочтения — 7 мин.
Получить бесплатную консультацию
Думаю, каждый программист рано или поздно сталкивался с подобной задачей: как реализовать проверку на наличие дублирующихся строк в табличных частях. Кому-то просто нужно проверить: есть, или нет, дубли. Кому-то нужно известить пользователя, и сообщить ему номера строк с дублями. Это вопросы будут рассмотрены в данной статье. Но давайте сразу определимся с терминологией: поля, по которым будет осуществляться контроль, назовем «ключевые».
Итак, предположим, что у нас стоит задача проверить наличие дублей строк табличной части по ключевым полям. Пусть это будет документ «Реализация товаров, услуг», дубли строк мы будем искать в табличной части «Товары», а в качестве ключевых полей будем использовать следующие реквизиты табличной части: Качество, Номенклатура, Склад, СерияНоменклатуры и ХарактеристикаНоменклатуры.
Рассмотрим следующие ситуации:
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) Если активен флажок «Сгенерировать и показать код для проверки на дубли», то будет сгенерирован программный код для выполнения проверки на дубли строк с имеющимися настройками.
Автор статьи:
Эксперт по технологическим вопросам ИнфоСофт
+7
Универсальная процедура проверки на дубли строк в табличной части документа
//Процедура проверяет наличие в ТЧ дублей строк по указанным реквизитам
//ДокументСсылка - ссылка на проверяемый документ
//ИмяТабЧасти - имя проверяемой табличной части (строка)
//ПроверяемыеРеквизиты - перечень проверяемых реквизитов (строка, реквизиты разделяются запятой)
Процедура ПроверимДублиСтрок(ДокументСсылка,ИмяТабЧасти,ПроверяемыеРеквизиты,Отказ)
ТаблицаДокумента = ДокументСсылка[ИмяТабЧасти].Выгрузить();
ТаблицаДокумента.Колонки.Добавить("КвоПроверкаДублей");
ТаблицаДокумента.ЗаполнитьЗначения(1, "КвоПроверкаДублей");
ТаблицаДокумента.Свернуть(ПроверяемыеРеквизиты,"КвоПроверкаДублей");
Для Каждого ТекущаяСтрока Из ТаблицаДокумента Цикл
Если ТекущаяСтрока.КвоПроверкаДублей > 1 Тогда
РеквизитыДляСообщения = "";
Стр = СокрЛП(ПроверяемыеРеквизиты);
Пока Найти(Стр,",") > 0 Цикл
НаимРеквизита = СокрЛП(Лев(Стр,Найти(Стр,",") - 1));
Стр = Прав(Стр,СтрДлина(Стр) - Найти(Стр,","));
РеквизитыДляСообщения = РеквизитыДляСообщения+ТекущаяСтрока[НаимРеквизита]+", ";
КонецЦикла;
РеквизитыДляСообщения = РеквизитыДляСообщения+ТекущаяСтрока[СокрЛП(Стр)];
Сообщить("Информация "+РеквизитыДляСообщения+" введена несколько раз в табличную часть, проведение невозможно!");
Отказ = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Пример обращения к процедуре проверки
Код 1C v 8.2 УП
// Процедура - обработчик события ОбработкаПроверкиЗаполнения объекта.
//
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если Запасы.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ПроверимДублиСтрок(Ссылка, "Запасы", "Номенклатура, АлгоритмФормированияШК,Регион", Отказ);
КонецПроцедуры
Да, в списке реквизитов добавленные случайно пробелы игнорируются
Процедуру можно добавить в общий модуль и обращаться к ней из любого документа
Поиск дублей в табличной части документа |
Я |
23.12.12 — 22:35
Документ записан. Как проверить есть ли в табличной части документа дубли, если есть то удалить и сообщить? Обшарила форумы ничего подходящего не нашла. Заранее благодарна за помощь.
1 — 23.12.12 — 22:36
запросом?
2 — 23.12.12 — 22:37
(1) Запрос.Текст = «ВЫБРАТЬ
| Товары.Код
|ИЗ
| ДокПоступление.Товары КАК Товары
|
|СГРУППИРОВАТЬ ПО
| Товары.Код»;
?
3 — 23.12.12 — 22:39
(2) Фотку?
4 — 23.12.12 — 22:45
да, без фотки никак
5 — 23.12.12 — 22:46
какая еще фотка?
6 — 23.12.12 — 22:46
Пол: Женский
Какая, какая… Твоя.
7 — 23.12.12 — 22:46
(5) с такими вопросами как (0) только топлес
8 — 23.12.12 — 22:47
(5) месяц на форуме а обычи так и не узнала )
9 — 23.12.12 — 22:50
(2) Посчитать количество различных и выбрать те, которые больше 1.
10 — 23.12.12 — 22:50
да тут одни джентльмены!
11 — 23.12.12 — 22:51
(10) что не по-джентельменски?
12 — 23.12.12 — 22:51
(9) можете привести пример?
13 — 23.12.12 — 22:53
Модам, вы неверно хотите это проверять перед записью документа?
14 — 23.12.12 — 22:54
(13) нет, после записи
15 — 23.12.12 — 22:55
«ВЫБРАТЬ
| Контрагенты.Код,
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|
|СГРУППИРОВАТЬ ПО
| Контрагенты.Код
|
|ИМЕЮЩИЕ
| СУММА(1) > 1″
нечто
16 — 23.12.12 — 22:55
это не принципиально, то есть это должно выполняться в интерфейсе и пользователя сразу оповещать?
17 — 23.12.12 — 22:57
(15) мне нужно проверить в таб. части, а это не то
18 — 23.12.12 — 22:57
После записи — смысл этой проверки ?
Или это будет проверяться потом, чтобы «зверям отвесить по полной» ?
19 — 23.12.12 — 22:58
(16) думаю что ОбработкаПроверкиЗаполнения
20 — 23.12.12 — 22:58
(17) А что мешает выбирать из табличной части ?
Открыли конструктор запросов и мышкуем по нужным полям.
21 — 23.12.12 — 23:00
(19) Если в ОбработкаПроверкаЗаполнения, то выгрузить табличную часть, добавить колонку — проставить единицу в неё, свернуть табличную часть, суммируя по колонке с единицей — ну и перебрать потом, чтобы пользователю сообщить, где он не прав.
22 — 23.12.12 — 23:00
(20) знания, не знаю как это сделать…
23 — 23.12.12 — 23:02
(21) какой изврат
24 — 23.12.12 — 23:03
(21)Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
| Товары.Код
|ИЗ
| НовыйДокПоступление.Товары КАК Товары
|
|СГРУППИРОВАТЬ ПО
| Товары.Код»;
Результат = Запрос.Выполнить();
ТЗ = Новый ТаблицаЗначений;
Результат.Выгрузить(ТЗ);
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку()=1 Цикл
ВыбратьСтроки();
Пока ПолучитьСтроку()=1 Цикл
Если (ТЗ.Код = Код)
И (ТЗ.НомерСтроки<>НомерСтроки) Тогда
Сообщить («В строке №»+НомерСтроки+» имеется одинаковый код»);
КонецЕсли;
КонецЦикла;
КонецЦикла;
25 — 23.12.12 — 23:03
Я так думаю что ей нужно в событии формы «ПередЗаписьюНаСервер» организовать обход строк табличной части, в этом обходе данные текущей строки сравниваются с данными строк где номер строки больше текущего, и при совпадении создавать СообщениеПользователю в котором ссылаться на текущую строку, таким образом мы не только не запишем ошибочный документ, но и тыкнем пользователя носом.
26 — 23.12.12 — 23:04
(25) все верно)
27 — 23.12.12 — 23:05
Вот моя умничка, я знал что вы никогда не скажите что хотите
28 — 23.12.12 — 23:05
Ну чтож пример кода придумать или сама?
29 — 23.12.12 — 23:06
цель проверять на коды, если в строке имеются одинаковые коды элементов, то удалить их и сообщить об этих строках
30 — 23.12.12 — 23:06
(27) а не проще сворачивать по-умолчанию?
31 — 23.12.12 — 23:07
(28) не получается у меня…((
32 — 23.12.12 — 23:09
DrShad эт идея, ток надо не сварачивать а в событии таблицы ОкончаниеРедактирования проверять на совпадение с другими строками , если да удалять эту и сообщить пользователю что он дурак
33 — 23.12.12 — 23:09
Модмозель, вы определитесь пока с вариантом исполнения, а примеры кода после фотографии (не всёж на халяву)
34 — 23.12.12 — 23:19
Мужики я сделал это!!!!!))))))))))))))
35 — 23.12.12 — 23:23
что ты сделал?
36 — 23.12.12 — 23:24
DrShad ты опоздал, фотка висела пару минут
37 — 23.12.12 — 23:27
Эх походу кто-то обиделся и примеры кода не нужны, ладно ещё 3 минуты посмотрю потом закрою страничку.
38 — 23.12.12 — 23:29
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
ТЗ=Товары.Выгрузить();
ТЗ.Сортировать(«Товар, НомерСтроки»);
тов=неопределено;
ст=»»;
нтов=ложь;
для каждого стр из ТЗ Цикл
Если стр.Товар=тов тогда
ст=ст+»,»+строка(стр.НомерСтроки);
нтов=истина;
Иначе
Если нтов тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = тов.Наименование+» содержиться в нескольких строках «+ст;
Сообщение.Сообщить();
отказ = истина;
КонецЕсли;
ст=строка(стр.НомерСтроки);
нтов=Ложь;
тов=стр.Товар;
КонецЕсли;
КонецЦикла;
Если нтов тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = тов.Наименование+» содержиться в нескольких строках «+ст;
Сообщение.Сообщить();
отказ = истина;
КонецЕсли;
КонецПроцедуры
39 — 23.12.12 — 23:32
(38) за такой код, человек его написавший уже бы не работал у нас, ничего личного, но не стоит учить плохому начинающих
40 — 23.12.12 — 23:33
ERWINS есть одно но, небудет подсветки на ошибочную строку если в модуле объекта.
41 — 23.12.12 — 23:34
(38) а не проще выгрузить только колонку товары, добавить числовую колонку — запонить ее единичкой потом свернуть и там гле будет больше единицы вывести на экран…код в 3 строчки.
42 — 23.12.12 — 23:35
(39) и чем плохо кроме имен переменных?
(40) тогда делать по другому, тоже не сложно
43 — 23.12.12 — 23:35
(41) зачем!? не проще сделать тоже самое запросом к ТЧ?
44 — 23.12.12 — 23:35
(32) Помоему самый верный вариант… зачем писать замудроватые запросы и усложнять запись документа… проще сразу проверять внесенные данные…
45 — 23.12.12 — 23:36
(42) например выгрузка в ТЗ и обход по ТЗ, а не сразу же по ТЧ
46 — 23.12.12 — 23:36
DrShad а как запрос делать к незаписанному объекту?
47 — 23.12.12 — 23:36
(43) запрос будет работать при условии, что документ уже записан.
48 — 23.12.12 — 23:36
(45) там вообще то сортировка…
сортировать табличную часть????
49 — 23.12.12 — 23:42
(48) а ее обязательно сортировать, чтоб найти дубли? имхо клюшечный код в снеговике
50 — 23.12.12 — 23:43
ERWINS а как твой код отработает, если две совпадающие строки будут в конце таблицы?
51 — 23.12.12 — 23:44
(49) что бы найти номера строк обязательно
52 — 23.12.12 — 23:44
а всё не посмотрел сначала.
53 — 23.12.12 — 23:44
(50) да, проверил
54 — 23.12.12 — 23:45
(53) если уж ты получил ТЗ, то скорми ее запросу и получи все дубли в результат
55 — 23.12.12 — 23:51
(54) зачем?
56 — 23.12.12 — 23:51
(48) извините за вопрос немного не по теме.
а почему нельзя сортировать табличную часть? судя по количеству вопросительных знаков в конце вашего возмущенного вопроса речь идет о чем-то предельно порочном и некрасивом…
57 — 23.12.12 — 23:52
(55) потому что сортировка ТЗ тормознутый метод
потому что дублей может и не быть, а цикл пройдет всю ТЗ и это тоже время
потому что так кошернее
58 — 23.12.12 — 23:53
(56) ее потом с оригиналом не удобно сверять, к примеру ввод ПТиУ
59 — 23.12.12 — 23:56
(56) потому что я не знаю, можно ли произвольно в документе менять порядок строк.
Иногда это бывает черевато
60 — 23.12.12 — 23:57
(58) ну это первое и единственное, что пришло мне в голову да. просто такое количество вопросительных знаков… думал может за этим кроется что-то еще
61 — 23.12.12 — 23:59
(60) просто я один раз так сделал, а потом объяснялся с лдьми из росалкоголя
62 — 23.12.12 — 23:59
(59) документ в котором нельзя меня порядок строк в табличной части это какой-то плохой документ как мне кажется. что-то есть неправильное в таком документе
63 — 24.12.12 — 00:02
(61) бред какой-то… но вобщем наши регулирующие органы никогда не были средоточием здравого смысла
64 — 24.12.12 — 00:20
модуль формы перед записью на сервере
ТЗДок = ТекущийОбъект.Товары.Выгрузить();
Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
| Товары.Код
| КОЛИЧЕСТВО(Товары.Номенклатура) КАК КоличествоДублей
|ИЗ
| &ТабличканяЧастьДок КАК Товары
|
|СГРУППИРОВАТЬ ПО
| Товары.Код»;
Запрос.УстановитьПараметр(«ТабличканяЧастьДок»,ТЗДок);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.КоличествоДублей>1 Тогда
Отбор = Новый Структура(«Код», Выборка.Код);
НайденыеСтроки = ТекущийОбъект.Товары.НайтиСтроки(Отбор);
Если НайденыеСтроки.Количество()>0 Тогда
Для Сч=1 По НайденыеСтроки.Количество()-1 Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Удалена строка с номенклатурой»+НайденыеСтроки[Сч].Номенклатура;
Сообщение.Сообщить();
ТекущийОбъект.Товары.Удалить(НайденыеСтроки[Сч]);
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЦикла;
65 — 24.12.12 — 00:27
(0) Выгрузить ТЧ в ТЗ, свернуть ТЗ по колонкам, где могут быть дубли, сравнить количество строк свернутой ТЗ и оригинальной ТЧ. Если разошлись количества строк — значит есть дубли. А вот уже потом искать любыми производительными способами дубли и сообщать о них пользователю.
А то часто видел код проверки на дубли, который очень долго ищет их там, где их нет…
66 — 24.12.12 — 00:30
(0) Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Для Каждого ТекСтрока Из ТЧ Цикл
ТекНоменклатура = ТекСтрока.Номенклатура;
НомерСтрк = ТекСтрока.НомерСтроки;
Для Каждого Стрк ИЗ ТЧ Цикл
Если Стрк.Номенклатура = ТекНоменклатура И Стрк.НомерСтроки <> НомерСтрк Тогда
ТЧ.Удалить(Стрк);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «дубли строк очищены»;
Сообщение.Сообщить();
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
67 — 24.12.12 — 00:34
&НаКлиенте
перем ЕстьДубликаты;
&НаКлиенте
Функция ПроверкаДубликатов()
для каждого стр из Объект.Товары цикл
стр.ДублирующаяСтрока=ложь;
конецЦикла;
МассивПервый=новый Массив;
МассивВторой=новый Массив;
для каждого стр из Объект.Товары цикл
Если МассивПервый.Найти(стр.Товар)=неопределено тогда
МассивПервый.Добавить(стр.Товар);
иначеЕсли МассивВторой.Найти(стр.Товар)=неопределено тогда
МассивВторой.Добавить(стр.Товар);
КонецЕсли
конецЦикла;
для каждого стр из Объект.Товары цикл
стр.ДублирующаяСтрока=не (МассивВторой.Найти(стр.Товар)=неопределено);
КонецЦикла;
ЕстьДубликаты=МассивВторой.Количество()>0;
возврат ЕстьДубликаты;
КонецФункции // ПроверкаДубликатов()
&НаКлиенте
Процедура ТоварыПриИзменении(Элемент)
ПроверкаДубликатов()
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПроверкаДубликатов()
КонецПроцедуры
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
Если ЕстьДубликаты тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «В табличной части Товары есть дубликаты»;
Сообщение.Сообщить();
отказ=истина;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриПовторномОткрытии()
ПроверкаДубликатов()
КонецПроцедуры
68 — 24.12.12 — 00:34
(66) больше никому это не показывай
69 — 24.12.12 — 00:35
(68) почему?
70 — 24.12.12 — 00:36
(66) Представляю что будет с таб частью в 50 строк… Можно записать документ и пойти пообедать)))
71 — 24.12.12 — 00:40
(69) во-первых двойной цикл
во-вторых удаление строк с нарушением выборки
72 — 24.12.12 — 00:41
(71) где ты видишь удаление строк????
какой двойной цикл?
73 — 24.12.12 — 00:44
(71) Таки да, если это и будет работать, то только при обратном обходе.
(72) Не тупи, мы коментируем не твой код.
74 — 24.12.12 — 00:46
(73) понял, извини
удаление строк в двойном цикле это минное поле
75 — 24.12.12 — 00:46
(74) иди уже отдыхать
76 — 24.12.12 — 03:47
(64) Пока самый близкий вариант… Но опять же обход всей Табличной части (а если нету дублей?)
77 — 24.12.12 — 03:50
Тоже самое но с условием в запросе
ТЗДок = ТекущийОбъект.Товары.Выгрузить();
Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
| Товары.Код
| КОЛИЧЕСТВО(Товары.Номенклатура) КАК КоличествоДублей
| Поместить ВТ
|ИЗ
| &ТабличканяЧастьДок КАК Товары
|
|СГРУППИРОВАТЬ ПО
| Товары.Код»;
|;
| Выбрать ВТ.Код
|ИЗ ВТ КАК ВТ
|ГДЕ ВТ.КоличествоДублей > 1
Запрос.УстановитьПараметр(«ТабличканяЧастьДок»,ТЗДок);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Отбор = Новый Структура(«Код», Выборка.Код);
НайденыеСтроки = ТекущийОбъект.Товары.НайтиСтроки(Отбор);
Если НайденыеСтроки.Количество()>0 Тогда
Для Сч=1 По НайденыеСтроки.Количество()-1 Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Удалена строка с номенклатурой»+НайденыеСтроки[Сч].Номенклатура;
Сообщение.Сообщить();
ТекущийОбъект.Товары.Удалить(НайденыеСтроки[Сч]);
КонецЦикла;
КонецЕсли;
КонецЦикла;
78 — 24.12.12 — 03:59
Или же примитив:
ТЗДок = ТекущийОбъект.Товары.Выгрузить();
ТЗДок.Колонки.Добавить(«КоличествоДублей»);
ТЗДок.ЗаполнитьЗначения(1,»КоличествоДублей»);
ТЗДок.Свернуть(«Номенклатура»,»КоличествоДублей»);
Для каждого Стр Из ТЗДок Цикл
Если Стр.КоличествоДублей > 1 тогда
Отбор = Новый Структура(«Номенклатура», Стр.Номенклатура);
НайденыеСтроки = ТекущийОбъект.Товары.НайтиСтроки(Отбор);
Если НайденыеСтроки.Количество()>0 Тогда
Для Сч=1 По НайденыеСтроки.Количество()-1 Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Удалена строка с номенклатурой»+НайденыеСтроки[Сч].Номенклатура;
Сообщение.Сообщить();
ТекущийОбъект.Товары.Удалить(НайденыеСтроки[Сч]);
КонецЦикла;
КонецЕсли;
КонецЦикла;
79 — 24.12.12 — 09:14
В типовой БГУ в ОбщегоНазначения есть Функция ЭтоСтрокаДубль(ТабЧасть, СтрокаТабЧасти, СтруктураРеквизитов)
80 — 24.12.12 — 09:40
(64) и (78) Прежде чем искать чёрную кошку в тёмной комнате хотелось бы убедиться, что она там есть.
ТЗ = ЭтотОбъект.Товары.Выгрузить();
ТЗ.ЗаполнитьЗначения(1,»НомерСтроки»);
ТЗ.Свернуть(«Номенклатура»,»НомерСтроки»);
Если ЭтотОбъект.Товары.Количество() <> ТЗ.Количество() Тогда
Собщить(«Мадам, я дико извеняюсь, но у вас таки всё-таки есть проблема с дублями строк»);
Отказ = Истина;
…
КонецЕсли;
81 — 24.12.12 — 09:48
(77) Писал на ходу без отладок… так что уж извините…
А нащет этого |ГДЕ ВТ.КоличествоДублей > 1
может я и ошибаюсь, но помоему сначало срабатывает отбор, а потом групировка, не???
82 — 24.12.12 — 10:58
ВЫБРАТЬ РАЗЛИЧНЫЕ
ПоступлениеТоваровТовары.НомерСтроки КАК НомерСтроки,
ПоступлениеТоваровТовары.Номенклатура
ИЗ
Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваровТовары
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваровТовары1
ПО ПоступлениеТоваровТовары.Номенклатура = ПоступлениеТоваровТовары1.Номенклатура
ГДЕ
ПоступлениеТоваровТовары.Ссылка = &Ссылка
И ПоступлениеТоваровТовары1.Ссылка = &Ссылка
И ПоступлениеТоваровТовары.НомерСтроки <> ПоступлениеТоваровТовары1.НомерСтроки
УПОРЯДОЧИТЬ ПО
НомерСтроки
Единственно, нужно сначала ТЧ во временную таблицу кинуть, чтобы 2 раза не читать, но для краткости пока без ВТ.
83 — 24.12.12 — 11:20
(82) квадратичная зависимость… жесть, так нельзя
84 — 24.12.12 — 11:23
Каждый раз гонять данные на скл и обратно не есть гуд, это дополнительная нагрузка и значительные задержки, правда практически константные, лучше уж делать только на одном уровне трехзвенки (случай ошибок особый)
85 — 24.12.12 — 11:26
(83) Конечно нельзя, ведь правильно это делать циклами и без запросов, и для полного счастья всё это на клиенте.
86 — 24.12.12 — 11:32
(85) смотри (67)
87 — 24.12.12 — 11:35
(86) Так я про это и писал.
88 — 24.12.12 — 11:36
(87) на мой взгляд лучший вариант….
89 — 24.12.12 — 11:43
(88) А вот давай попросим знающих людей выбрать наилучший вариант из предложенных в данной теме. Если они сюда зайдут, конечно.
90 — 24.12.12 — 11:45
(89) хотелось бы
МихаилМ
91 — 24.12.12 — 12:11
(0)
вот эффективный алгоритм поиска дублей
Задача на поиск в массиве
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если Товары.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ПроверитьДублиСтрок(Ссылка, «Товары», «Номенклатура, ШтрихКод», Отказ);
КонецПроцедуры
//Процедура проверяет наличие в ТЧ дублей строк по указанным реквизитам
//ДокументСсылка — ссылка на проверяемый документ
//ИмяТабЧасти — имя проверяемой табличной части (строка)
//ПроверяемРеквизиты — перечень проверяемых реквизитов (строка, реквизиты разделяются запятой)
Процедура ПроверитьДублиСтрок(ДокументСсылка, ИмяТабЧасти, ПроверяемРеквизиты, Отказ)
ТаблДок = ДокументСсылка[ИмяТабЧасти].Выгрузить();
ТаблДок.Колонки.Добавить(«КоличПроверкаДублей»);
ТаблДок.ЗаполнитьЗначения(1, «КоличПроверкаДублей»);
ТаблДок.Свернуть(ПроверяемРеквизиты,«КоличПроверкаДублей»);
Для Каждого ТекСтрока Из ТаблДок Цикл
Если ТекСтрока.КоличПроверкаДублей > 1 Тогда
ДляСообщения = «»;
СтрРекв = СокрЛП(ПроверяемРеквизиты);
Пока Найти(СтрРекв,«,») > 0 Цикл
НаимРеквизита = СокрЛП(Лев(СтрРекв,Найти(СтрРекв,«,») — 1));
СтрРекв = Прав(СтрРекв,СтрДлина(СтрРекв) — Найти(СтрРекв,«,»));
ДляСообщения = ДляСообщения+ТекСтрока[НаимРеквизита]+«, «;
КонецЦикла;
ДляСообщения = ДляСообщения+ТекСтрока[СокрЛП(СтрРекв)];
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «В разделе « + ТекСтрока.Раздел + » одинаковые значения: « + ДляСообщения + «, сохранение невозможно»;
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Поиск дублей в таблице значений или табличном поле
16.05.2017
Проверка любой таблицы на повторяющиеся строки, с выводом сообщения какие строки задублированны, и режимом «Отказ» для проведения документов.
В данной процедуре поиск дублей происходит по всем колонкам строк. Тоесть дублем считается повтор значений в двух строках по всем колонкам.
Если повторяющих строк больше одной, то они все будут показаны в сообщении, с порядковым номером исходной строки и повторяющейся строки.
Данную процедура лучше использовать в общем модуле и вызывать её из процедур «ПриЗаписи» или «ОбработкаПроведения», и т.п. То есть в тех, где можно сделать отказ от выполнения дальнейших дествий
В качестве Таблицы — можно указать «ТаблицуЗначений», либо «ТабличнуюЧасть» документа, Справочника и т.д.
// !!! Павел С.С. 2 июня 2011 г. 17:49:14
// Проверка любой таблицы на повторяющиеся строки
// Данную процедура лучше использовать в процедурах ПриЗаписи, ОбработкаПроведения, и т.п. Тоесть в тех, где можно сделать отказ от выполениядальнейших дествий
// Параметры:
// ТЧ — можно указать «ТаблицуЗначений», либо «ТабличнуюЧасть» документа
// Отказ — параметр «Отказ» или «Истина», «Ложь»
Процедура ПоискДублейСтрокВТабЧасти(ТЧ, Отказ) Экспорт
Если Тип(ТЧ) = Тип(«ТаблицаЗначений») Тогда
ТаблЗнач = ТЧ;
Иначе
ТаблЗнач = ТЧ.Выгрузить();
КонецЕсли;
Отбор = Новый Структура();
Для каждого Стр Из ТаблЗнач Цикл
Отбор.Очистить();
Для каждого Колонки Из ТаблЗнач.Колонки Цикл
Если Колонки.Имя <> «НомерСтроки» Тогда
Отбор.Вставить(Колонки.Имя, Стр[Колонки.Имя]);
КонецЕсли;
КонецЦикла;
Строки = ТаблЗнач.НайтиСтроки(Отбор);
Если Строки.Количество() > 1 Тогда
Для каждого НайденныеСтроки Из Строки Цикл
Если Строки.Найти(НайденныеСтроки) > 0 Тогда
СтрокаСообщения = «Строка № » + Строки[0].НомерСтроки + » совпадает со строкой № » + НайденныеСтроки.НомерСтроки;
СообщитьОбОшибке(СтрокаСообщения, Отказ, «Уберите задвоения строк!»);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецПроцедуры