Поиск дублей в таблице значений или табличном поле
16.05.2017
Проверка любой таблицы на повторяющиеся строки, с выводом сообщения какие строки задублированны, и режимом “Отказ” для проведения документов.
В данной процедуре поиск дублей происходит по всем колонкам строк. Тоесть дублем считается повтор значений в двух строках по всем колонкам.
Если повторяющих строк больше одной, то они все будут показаны в сообщении, с порядковым номером исходной строки и повторяющейся строки.
Данную процедура лучше использовать в общем модуле и вызывать её из процедур “ПриЗаписи” или “ОбработкаПроведения”, и т.п. То есть в тех, где можно сделать отказ от выполнения дальнейших дествий
В качестве Таблицы — можно указать “ТаблицуЗначений”, либо “ТабличнуюЧасть” документа, Справочника и т.д.
// !!! Павел С.С. 2 июня 2011 г. 17:49:14
// Проверка любой таблицы на повторяющиеся строки
// Данную процедура лучше использовать в процедурах ПриЗаписи, ОбработкаПроведения, и т.п. Тоесть в тех, где можно сделать отказ от выполениядальнейших дествий
// Параметры:
// ТЧ — можно указать «ТаблицуЗначений», либо «ТабличнуюЧасть» документа
// Отказ — параметр «Отказ» или «Истина», «Ложь»
Процедура ПоискДублейСтрокВТабЧасти(ТЧ, Отказ) Экспорт
Если Тип(ТЧ) = Тип(«ТаблицаЗначений») Тогда
ТаблЗнач = ТЧ;
Иначе
ТаблЗнач = ТЧ.Выгрузить();
КонецЕсли;
Отбор = Новый Структура();
Для каждого Стр Из ТаблЗнач Цикл
Отбор.Очистить();
Для каждого Колонки Из ТаблЗнач.Колонки Цикл
Если Колонки.Имя <> «НомерСтроки» Тогда
Отбор.Вставить(Колонки.Имя, Стр[Колонки.Имя]);
КонецЕсли;
КонецЦикла;
Строки = ТаблЗнач.НайтиСтроки(Отбор);
Если Строки.Количество() > 1 Тогда
Для каждого НайденныеСтроки Из Строки Цикл
Если Строки.Найти(НайденныеСтроки) > 0 Тогда
СтрокаСообщения = «Строка № » + Строки[0].НомерСтроки + » совпадает со строкой № » + НайденныеСтроки.НомерСтроки;
СообщитьОбОшибке(СтрокаСообщения, Отказ, «Уберите задвоения строк!»);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Поиск “дублей” в таблице значений |
Я |
14.03.06 – 17:41
Как в таблице значений найти записи с одинаковыми колонками? Есть таблица значений из 11 колонок, из них две РасчетныйСчет и КодБанка. Надо оставить строки с повторяющимися значениями колонок РасчетныйСчет и КодБанка, те оставить строки с неуникальными значениями этих колонок. Подскажите какие нибудь идеи к алгоритму.
1 – 14.03.06 – 17:43
Самая простая идея: Свернуть()…
2 – 14.03.06 – 17:45
+ (1) На всякий случай Свернуть, Свернуть, Свернуть…
3 – 14.03.06 – 17:46
Перед КонецЦикла запоминаешь значение.
После начала цикла сравниваешь новое значение с запомненным. Если равно – дубль
4 – 14.03.06 – 17:46
(3) Афигеть…
5 – 14.03.06 – 17:46
(3) + ест-но перед циклом сортировка по искомому полю
6 – 14.03.06 – 17:47
(3) по двум искомым полям? )
7 – 14.03.06 – 17:47
+ (4) А первое значение с чем сравнивать с “пустышкой” ?
8 – 14.03.06 – 17:47
(4) Афигевай
9 – 14.03.06 – 17:47
(0) Может проще на этапе формирования?
Для к=1 по ТЗ.КоличествоСтрок Цикл
ТЗ.ПолучитьСтроку(к);
Если ТЗ.РасчетныйСчет<>ТЗ.КодБанка Тогда
ТЗ.УдалитьСтроку(к)
КонецЕсли;
КонецЦикла;
10 – 14.03.06 – 17:48
(9) Ты этт счас придумал
(8) А Свернуть нафиха тогда есть?
11 – 14.03.06 – 17:48
уж сотка ближется, а автора все нет…
12 – 14.03.06 – 17:50
(6) – по двум полям – два прогона ТЗ.
(10) И что ты узнаешь в результате сворачивания ? Разве что в доп.поле единицу прописать перед сворачиванием в каждую строку. Потом проверять на Если >=2
13 – 14.03.06 – 17:50
Я подожду (цы)
14 – 14.03.06 – 17:52
Метод удаления строк из конкурса с проклаба (не помню кто автор):
Перем ТЗ_СЛУЖ;
тз = СоздатьОбъект(“ТаблицаЗначений”);
//тз – исходная табличка значений
//Заполнение тз:
………………
// Удалим не дубли
КонСтрока=Мин(тз.НоваяКолонка(“СЛУЖ_КОЛ”), 0);
тз.ВыбратьСтроки();
Пока тз.ПолучитьСтроку()=1 Цикл
Если ТЗ.РасчетныйСчет=ТЗ.КодБанка Тогда
КонСтрока=КонСтрока+1;
тз.СЛУЖ_КОЛ=1;
КонецЕсли;
КонецЦикла;
Если (КонСтрока=0) ИЛИ (КонСтрока=тз.КоличествоСтрок()) Тогда
тз.КоличествоСтрок(КонСтрока);
тз.УдалитьКолонку(“СЛУЖ_КОЛ”);
Иначе
тз.Сортировать(“-СЛУЖ_КОЛ”);
тз.УдалитьКолонку(“СЛУЖ_КОЛ”);
тз.Выгрузить(ТЗ_СЛУЖ,,КонСтрока);
тз=ТЗ_СЛУЖ;
КонецЕсли;
15 – 14.03.06 – 17:52
(11) Тута я. Читаю и думаю что применять…
16 – 14.03.06 – 17:53
(10) Ваш код в студию
ТЗ.Свернуть(1,2,3,4,5,6,7,8,9,10,11) Вы так предлагаете?
17 – 14.03.06 – 17:53
(12)
Вы не знаете кто такой Паниковский?
Нет, Вы не знаете кто такой Паниковский…
Тогда поезжайте в Киев и спросите.
Спросите…
Нет, Вы поезжайте и спросите… (с)
18 – 14.03.06 – 17:53
(15) Ну а если что б оставить только уникальные – то см.(9) тока, как говорится сзаду надо это делать. Ну и два прогона – по любому.
19 – 14.03.06 – 17:54
(16) Не пристало мне код тута писать на такой “тривиал” 🙂
Модератор
20 – 14.03.06 – 17:54
тз=СоздатьОбъект("ТаблицаЗначений"); тз.НоваяКолонка("РассчетныйСчет"); тз.НоваяКолонка("КодБанка"); тз.НоваяКолонка("Количество"); //Заполняем единицами Количество тз.Заполнить(1,,,"Количество"); ... тз.Свернуть("РассчетныйСчет,КодБанка","Количество");
Теперь в графе количество будет 2 и более если задвоены строки.
22 – 14.03.06 – 17:55
(18) По любому ?
23 – 14.03.06 – 17:55
(22) По любому – для простоты. Из принципа – ест-но и гланды можно снизу выдрать
24 – 14.03.06 – 17:56
🙂
Пусть скажет аффтар в (0)
25 – 14.03.06 – 17:57
согласна с (19)
26 – 14.03.06 – 17:58
(25) В чем согласна?
27 – 14.03.06 – 17:59
(24) Вот (20) точно можно использовать, в (14) еще не врубилась
28 – 14.03.06 – 18:00
(27) Да, только не забудь, что нужно узнать не сам факт существования строк, а еще ведь и удалить их 🙂
29 – 14.03.06 – 18:01
(26) в том что “Не пристало мне код тута писать на такой “тривиал”
30 – 14.03.06 – 18:03
(27) так все в другую таблицу и там удалить строки у которых Количество>1
31 – 14.03.06 – 18:08
(28) Смотри (30)
32 – 14.03.06 – 18:11
(30) Их там еще нужно найти… а однозначно это сделать не получится
Короче перебирай строки таблицы и попутно найденные значения заноси в список, например
Если нет в списке – добавить, если есть – удалить тек. строку
Проще, конечно, при формировании ТЗ это сделать
Долго, но верно
ЗЫ. имхо
Модератор
33 – 14.03.06 – 18:15
(28) Два вложенных цикла. По свернутой таблице и по искомой.
Не забывать делать ВыбратьСтроки(); после каждого удаления строки.
Тупой надежный алгоритм. Но при больших таблицах может выполняться долго.
34 – 14.03.06 – 18:18
(32) Однозначно получиться – пронумеровать строки то я могу (Добавить еще одну колонку в ТаблицуЗначений). Но мой метод через две таблицы
(33) Вот так и попробую сделать. спасибо
35 – 14.03.06 – 18:18
Уж тогда уж Сортировать()… и далее…
36 – 14.03.06 – 18:22
Всеж непонял, а чем Свернуть неглянется ?
Поясните для тупых и алкоголиков…(правдо)
Млж чего и посоветую, и вопряки (19) код койнибудь напишу…
37 – 14.03.06 – 18:22
(33) Мдя… зачем два, когда можно ОДНИМ?
(34) Угумс… пронумеровать и благополучно свернуть 🙂
38 – 14.03.06 – 18:40
(0) А в колонках значения повторяются?
39 – 14.03.06 – 18:50
Мулька в (3)+(5) самую правильную наводку дал …
А всё остальное, что здесь сказали – чушь собачья!
40 – 14.03.06 – 18:53
(39) эт точно 🙂
41 – 14.03.06 – 18:56
+(3) + (5) + (39) Свертка ни при чем.
Можно такой алгоритм.
1. Таб2 с колонками “ОбщийСчет”,”Ссылка”
2. Данные из ТЗ в Таб2 построчно:
Таб2.ОбщийСчет=ТЗ.РасчетныйСчет;
Таб2.Ссылка=ТЗ.НомерСтроки;
3. Данные из ТЗ в Таб2 повторно:
Таб2.ОбщийСчет=ТЗ.КодБанка;
Таб2.Ссылка=ТЗ.НомерСтроки;
4. Сортировка
Таб2.Сортировать(“ОбщийСчет”);
5. Удаление строк из Таб2 для которых “ОбщийСчет” не повторяется.
6. Сортировка Таб2 по “Ссылка” – итог: номера строк в ТЗ, которые надо оставить.
42 – 14.03.06 – 19:01
(39) А это полная лажо ?
Процедура Сформировать()
ТЗ=СоздатьОбъект(“ТаблицаЗначений”);
ТЗ.НоваяКолонка(“КодБанка”);
ТЗ.НоваяКолонка(“РасчетныйСчет”);
ТЗ.НоваяКолонка(“названиеБанка”);
ТЗ.НоваяКолонка(“Остаток”);
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 1;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “Пупкинский”;
ТЗ.Остаток = 256;
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 1;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “ЗаПупкинский”;
ТЗ.Остаток = 256;
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 2;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “ОччПупкинский”;
ТЗ.Остаток = 253;
ТЗ.Свернуть(“КодБанка,РасчетныйСчет”,”НазваниеБанка,Остаток”);
ТЗ.ВыбратьСтроку();
КонецПроцедуры
43 – 14.03.06 – 19:09
(42) Не буянь, лажевинько…
44 – 14.03.06 – 19:12
(43) Но ведь (0) решает, кто не верит (не о тебе) может проверить…(дублито сказано тока по 2 колонкам зырить, знчит значения остальных пох какое выйдет, хотя могу кинуть чтоб и все значения было видно, при чем будет “приляпано” к тем двум калонкам)
45 – 14.03.06 – 19:13
+(44) Если есть колонки с числовым значением но их ссумировать ненада, то легко преобразуются до текстовых перед тем как…
46 – 14.03.06 – 19:16
(44)Так вот и надо, получается, эти дубляные строки совсем не трогать… Я сам (0) по диагонали прочитал… Криво здесь Свёртывать()…
Из принципа можно и её прикрутить, но это будет “пятая нога”…
47 – 14.03.06 – 19:18
(45) Так к чему не преобразовывай, а данные из других колонок потеряешь…
48 – 14.03.06 – 19:19
(46)(47) Тогда решения для (0) нету кроме (44) в скобочках после второй запятой…
49 – 14.03.06 – 19:20
(44) не решает.
50 – 14.03.06 – 19:20
+(48) “…после первой запятой”
51 – 14.03.06 – 19:22
(49) Почитай (0) сказано по двум колонкам? – сказано, тогда остальные как уж получатся, суммы будут верны, а строки/субконтывсякие будут по первой, хотя в (44) в скобочках есть вариант чтоб и все другие колонки остались целы….
52 – 14.03.06 – 19:24
+(51) а вот как сделать чтоб было по 2 колонкам, но остальные видны – думайте, я “в танке”, нескажу…
53 – 14.03.06 – 19:24
(51) смотря что ты будешь делать после (42) Но в любом случае, свертка по 2 полям лишняя.
54 – 14.03.06 – 19:25
(53) Ты пробовал ? все что в (0) описано сделано, остальное в (44) и (52)…
55 – 14.03.06 – 19:26
КодБанка РасчетныйСчет
2 4
4 2
После свертки останется в первозданном виде.
56 – 14.03.06 – 19:29
(55) Да ну на… ты в точности повторил ?
КодБанка РасчетныйСчет НазваниеБанка Остаток
1 2 Пупкинский 512
2 2 ОччПупкинский2 253
57 – 14.03.06 – 19:31
Или такая лажо
Процедура Сформировать()
ТЗ=СоздатьОбъект(“ТаблицаЗначений”);
ТЗ.НоваяКолонка(“КодБанка”);
ТЗ.НоваяКолонка(“РасчетныйСчет”);
ТЗ.НоваяКолонка(“названиеБанка”);
ТЗ.НоваяКолонка(“Остаток”);
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 1;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “Пупкинский”;
ТЗ.Остаток = 256;
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 2;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “ОччПупкинский”;
ТЗ.Остаток = 253;
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 1;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “ЗаПупкинский”;
ТЗ.Остаток = 256;
ТЗ.НоваяСтрока();
ТЗ.КодБанка = 2;
ТЗ.РасчетныйСчет = 2;
ТЗ.названиеБанка = “ччПупкинский”;
ТЗ.Остаток = 253;
ТЗ.Свернуть(“КодБанка,РасчетныйСчет”,”НазваниеБанка,Остаток”);
ТЗ.ВыбратьСтроку();
КонецПроцедуры
58 – 14.03.06 – 19:34
(57) крылья крылья… Хвост! на.. тебе свертка? Сортировка + прогон для повторов которые идут подряд! Сначала для “КодБанка” потом для “Расчетного счета”. Как и говорил Мулька.
smaharbA
59 – 14.03.06 – 19:38
(58) А на сортировать и прогонять если и так все решается, если конечно условия сложнее тогда мож и сортировать…
Проверка на наличие дублирующихся строк в табличных частях
Время прочтения – 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 Тогда
Возврат;
КонецЕсли;
ПроверимДублиСтрок(Ссылка, "Запасы", "Номенклатура, АлгоритмФормированияШК,Регион", Отказ);
КонецПроцедуры
Да, в списке реквизитов добавленные случайно пробелы игнорируются
Процедуру можно добавить в общий модуль и обращаться к ней из любого документа
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если Товары.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ПроверитьДублиСтрок(Ссылка, “Товары”, “Номенклатура, ШтрихКод”, Отказ);
КонецПроцедуры
//Процедура проверяет наличие в ТЧ дублей строк по указанным реквизитам
//ДокументСсылка – ссылка на проверяемый документ
//ИмяТабЧасти – имя проверяемой табличной части (строка)
//ПроверяемРеквизиты – перечень проверяемых реквизитов (строка, реквизиты разделяются запятой)
Процедура ПроверитьДублиСтрок(ДокументСсылка, ИмяТабЧасти, ПроверяемРеквизиты, Отказ)
ТаблДок = ДокументСсылка[ИмяТабЧасти].Выгрузить();
ТаблДок.Колонки.Добавить(“КоличПроверкаДублей”);
ТаблДок.ЗаполнитьЗначения(1, “КоличПроверкаДублей”);
ТаблДок.Свернуть(ПроверяемРеквизиты,“КоличПроверкаДублей”);
Для Каждого ТекСтрока Из ТаблДок Цикл
Если ТекСтрока.КоличПроверкаДублей > 1 Тогда
ДляСообщения = “”;
СтрРекв = СокрЛП(ПроверяемРеквизиты);
Пока Найти(СтрРекв,“,”) > 0 Цикл
НаимРеквизита = СокрЛП(Лев(СтрРекв,Найти(СтрРекв,“,”) – 1));
СтрРекв = Прав(СтрРекв,СтрДлина(СтрРекв) – Найти(СтрРекв,“,”));
ДляСообщения = ДляСообщения+ТекСтрока[НаимРеквизита]+“, “;
КонецЦикла;
ДляСообщения = ДляСообщения+ТекСтрока[СокрЛП(СтрРекв)];
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “В разделе “ + ТекСтрока.Раздел + ” одинаковые значения: “ + ДляСообщения + “, сохранение невозможно”;
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры