|   |   | 
| 
 | Поиск (и удаление) не повторяющихся значений в таблице... | ☑ | ||
|---|---|---|---|---|
| 0
    
        new_hope 30.10.19✎ 15:16 | 
        Прошу, может кто знает действующий (и быстрый :-) алгоритм. Задача - ОСТАВИТЬ таблице (значений) те строки, которые повторяются два и более раз (то-есть удалить те строки, у которых нет повторов).
 Поиск нужно осуществлять по 2-м колонкам из множества колонок. | |||
| 1
    
        Beduin 30.10.19✎ 15:17 | 
        Свернуть     | |||
| 2
    
        vicof 30.10.19✎ 15:20 | 
        Формировать таблицу изначально нужно правильно, чтобы потом не заниматься всякой фигней     | |||
| 3
    
        Garykom гуру 30.10.19✎ 15:24 | 
        (0) Как это ни странно но данная задача лучше всего решается через запросы     | |||
| 4
    
        Garykom гуру 30.10.19✎ 15:25 | 
        (3)+ Засовываешь ТЗ в запрос и соединяешь с собой внутренним соединением по нужным колонкам.
 Причем чтобы исключить дубли (строка сама с собой) добавить условие на номер строки например. | |||
| 5
    
        new_hope 30.10.19✎ 15:27 | 
        (2) (3) Пытался разобраться через ЗАПРОС - но у меня из 4-х колонок в 3-х колонках ссылки не смог разобраться, так как ссылки не группируются. Короче - недостаточно знаний. Если есть готовый пример - ткните ссылку. Спасибо.     | |||
| 6
    
        new_hope 30.10.19✎ 15:29 | 
        (4) Мне дубли как раз нужно ВКЛЮЧАТЬ а не исключать. То что НЕ дублируется - вообще удалить (игнорировать) в результате     | |||
| 7
    
        Garykom гуру 30.10.19✎ 15:31 | 
        (6) У меня все правильно написано, именно только дубли и выберутся в результате запроса.     | |||
| 8
    
        vicof 30.10.19✎ 15:36 | 
        (0) Зачем ты это хочешь сделать?     | |||
| 9
    
        new_hope 30.10.19✎ 15:40 | 
        (8) т.к. это ошибочные значения и нужно знать о них и перейти по наборам ссылок этих значений     | |||
| 10
    
        Йохохо 30.10.19✎ 15:42 | 
        (9) ну и бахни, НайтиСтроки, давно не удаляли строк из ТЗ     | |||
| 11
    
        azernot 30.10.19✎ 15:48 | 
        Выбрать КОлонка1, Колонка2, 1 как КоличествоСтрок
 Поместить ЗначенияКолонок Из ТЗ ; Выбрать КОлонка1, Колонка2, Сумма(КОличествоСтрок) Поместить ПовторяющиесяКлючевыеКолонки Из ЗначенияКолонок Сгрупппировать по КОлонка1, Колонка2 Имеющие Сумма(КОличествоСтрок)>1 ; Выбрать * из ТЗ Внутреннее соединение ПовторяющиесяКлючевыеКолонки по ТЗ.Колонка1= ПовторяющиесяКлючевыеКолонки.Колонка1 И ТЗ.Колонка2= ПовторяющиесяКлючевыеКолонки.Колонка2 | |||
| 12
    
        new_hope 30.10.19✎ 15:49 | 
        (10) Так и думаю. Боюсь за скорость. Уверен, это можно сделать изящно запросом, но ума не хватает. :-(
 Есть колонки "Документ1Ссылка, Документ2Ссылка, Документ3Ссылка, Дата, Фамилия" Так вот, нужно в результате оставить все значения, которые ИМЕЮТ дубли по полям "Дата и Фамилия". и дата и номер - значения НЕ уникальные. | |||
| 13
    
        Йохохо 30.10.19✎ 15:49 | 
        (11) а типизировать?)     | |||
| 14
    
        pechkin 30.10.19✎ 15:50 | 
        можно без запроса. в 1 проход. просто проверять, что след строка не такая же и пред была не такая. значит эта строка единственная. тз вначале нужно отсортировать | |||
| 15
    
        pechkin 30.10.19✎ 15:51 | 
        ну или след строка такая же - добавляем строу в новую тз     | |||
| 16
    
        azernot 30.10.19✎ 15:54 | 
        (13) В запросе можно использовать только ТЗ с типизованными колонками. Так что ничего типизировать не надо. Или я не понимаю о чём ты...     | |||
| 17
    
        mistеr 30.10.19✎ 15:55 | 
        Сомневаюсь, что запросом всегда будет быстрее. Я бы сделал через Свернуть() и НайтиСтроки().     | |||
| 18
    
        Garykom гуру 30.10.19✎ 15:57 | 
        (14) (15) Слегка подумай, надо выбрать все строки (со всеми их колонками) имеющие дубли по двум колонкам.
 Условие выбора задолбаешься придумывать, в отличие от запроса. Тебе же надо выбрать и когда 2 и когда 3 и когда 4 строки и т.д. подряд имеют те же значения в паре колонок. Причем не пропустить и не накопировать лишнего в новую ТЗ. | |||
| 19
    
        D_E_S_131 30.10.19✎ 15:57 | 
        (12) Кинул свою ТЗ в запрос во временную таблицу. Соединил саму с собой по нужным полям (Дата и Фамилия). Поставил условие на поле из "дублирующей таблицы" "Есть НЕ Null".     | |||
| 20
    
        Garykom гуру 30.10.19✎ 15:58 | 
        (17) А вот это уже более разумный вариант но тормозной, так как сначала свертка а потом поиск в цикле по свернутым.     | |||
| 21
    
        Garykom гуру 30.10.19✎ 15:58 | 
        (19) см (4)     | |||
| 22
    
        azernot 30.10.19✎ 16:00 | 
        (19) Такой план всегда будет возвращать всю исходную ТЗ. :)     | |||
| 23
    
        Garykom гуру 30.10.19✎ 16:00 | 
        (0) ТС выложи плиз тестовую табличку если не секретно, кому интересно на разных методах сможет потестить скорость.     | |||
| 24
    
        Garykom гуру 30.10.19✎ 16:00 | 
        (22) Угу условие забыл исключения пар строк с самой собой, я предложил по номеру строки условие     | |||
| 25
    
        azernot 30.10.19✎ 16:00 | 
        +(22) нужно какое-то поле, позволяющие различать строки.. Типа "НомерСтроки". И ставить условие соединения по неравенству этого поля.     | |||
| 26
    
        mistеr 30.10.19✎ 16:07 | 
        (20) Не очевидно, что тормозной. На малых объемах не ощутимо, а на больших хз, нужно тестировать. Данные не гоняются на скуль и обратно, индексирование может помочь, в общем не очевидно.     | |||
| 27
    
        pechkin 30.10.19✎ 16:12 | 
        (18) ничего сложного нет. классическая задача на именно программирование | |||
| 28
    
        Garykom гуру 30.10.19✎ 16:12 | 
        (26) Проще тогда отсортировать, затем одним циклом проверять пары строк и находить начало и конец блока дубля строк.
 Ну и имея эти пары НачальнаяСтрока, КонечнаяСтрока получить эти строки. или вариация с накопителем, куда строки в цикле добавляются если равна следующая или если следующая строка не равна то если в накопителе >=2 строки их в новую ТЗ добавляем, а накопитель очищаем и т.д. | |||
| 29
    
        pechkin 30.10.19✎ 16:14 | 
        (28) ну тоже самое описал, про что я говорил в (15)     | |||
| 30
    
        azernot 30.10.19✎ 16:14 | 
        (17) Зачем сворачивать?
 Можно сделать в один цикл по ТЗ, с последующим удалением лишних МасивСтрокКУдалению = Новый Массив(); ТЗКлючевыхПолей = Новый ТаблицаЗначений; ТЗКлючевыхПолей.Колонки.Добавить("Колонка1", ТЗ.Колонки.найти("КОлонка1").ТипЗначения); ТЗКлючевыхПолей.Колонки.Добавить("Колонка2", ТЗ.Колонки.найти("КОлонка2").ТипЗначения); ТЗКлючевыхПолей.Колонки.Добавить("ПерваяСтрокаТЗ"); Для каждого СтрокаТЗ из ТЗ Цикл НайденныеСтроки = ТЗКлючевыхПолей.НайтиСтроки(Новый Структура("Колонка1, Колонка2", СтрокаТЗ.Колонка1, СтрокаТЗ.Колонка2); Если НайденныеСтроки.Количество()>0 ТОгда //Такие значения полей ранее уже встречались ИндексСтроки = МасивСтрокКУдалению.Найти(НайденныеСтроки[0].ПерваяСтрокаТЗ); Если НЕ ИндексСтроки = Неопределено ТОгда //Если первая строка с такими ключевыми полями числится к удалению, нужно убрать её оттуда МасивСтрокКУдалению.Удалить(ИндексСтроки); КонецЕсли; Продолжить; КОнецЕсли; //Сюда попадает только строка с ранее не встречающющимися значениями ключевых полей НоваяСтрокаКЛючевыхПолей = ТЗКлючевыхПОлей.Добавить(); ЗаполнитьЗначенияСвойств(НоваяСтрокаКЛючевыхПолей, СтрокаТЗ); НоваяСтрокаКЛючевыхПолей.ПерваяСтрокаТЗ = СтрокаТЗ; МасивСтрокКУдалению.Добавить(СтрокаТЗ); КонецЦикла; Для каждого УдаляемаяСтрока Из МасивСтрокКУдалению Цикл ТЗ.Удалить(УдаляемаяСтрока); КонецЦикла; | |||
| 31
    
        Garykom гуру 30.10.19✎ 16:16 | 
        (29) Ты упустил важную вещь про буфер, твой алгоритм правильно только для пар дубль строк а если их там триплеты и более не сработает.     | |||
| 32
    
        pechkin 30.10.19✎ 16:16 | 
        (31) почему? достаточно счетчик добавить. буфер не нужен     | |||
| 33
    
        Garykom гуру 30.10.19✎ 16:16 | 
        (30) Запросом сильно короче выглядит чем вот это длинное     | |||
| 34
    
        Garykom гуру 30.10.19✎ 16:17 | 
        (32) Два счетчика тогда     | |||
| 35
    
        azernot 30.10.19✎ 16:18 | 
        (33) Зато без передачи данных с сервера приложений на сервер баз данных и наоборот.     | |||
| 36
    
        pechkin 30.10.19✎ 16:19 | 
        (34) не нужно. предыдущую строку добавляем.если они совпадает с текущей. текущую добавляем, если счетчик > 1 при смене строки сбарсываем счетчик | |||
| 37
    
        azernot 30.10.19✎ 16:19 | 
        +(35) Хотя, может я неверно понимаю механизм запросов и в данном случае он не будет обращаться к серверу баз данных. Но почему-то я думаю, что это не так.     | |||
| 38
    
        mistеr 30.10.19✎ 16:23 | 
        (30) Сворачивать для того, чтобы не делать циклы по всей ТЗ.     | |||
| 39
    
        new_hope 30.10.19✎ 16:23 | 
        (23) А как выложить? Это не типовая конфа и как мне ссылки на документы выложить? Саму структуру таблички я указал (в реальной жизни вместо "Фамилия" - Строка с буквенно-цифровым значением :-)     | |||
| 40
    
        Ёпрст гуру 30.10.19✎ 16:24 | 
        (30) можно сделать еще проще, достаточно отсортировать тз по ключевым полям и дальше сравнение строк с предыдущей.
 Тогда НайтиСтроки в цикле не надо делать | |||
| 41
    
        Garykom гуру 30.10.19✎ 16:27 | 
        (39) Табличку екселя или csv файлик с данными колонок можно выкладывать     | |||
| 42
    
        Garykom гуру 30.10.19✎ 16:28 | 
        (40) Угу см (28)     | |||
| 43
    
        Креатив 30.10.19✎ 16:34 | 
        Присоединяюсь к тем ораторам, что за сортировку по ключевым полям и последующее сравнение строк.
 Единственно добавлю, что обход нужно делать снизу таблицы, чтобы при удалении строк что-нибудь не пошло не так. Не факт, что будет быстро, зато очень прозрачно. | |||
| 44
    
        new_hope 30.10.19✎ 16:34 | 
        (23) 
 Номер Док_1 Док_2 Док_3 Дата Фамилия 1 Документ_Тип1_Номер_1 Документ_Тип2_Номер_1 Документ_Тип3_Номер_1 01.01.2019 Вася 2 Документ_Тип1_Номер_2 Документ_Тип2_Номер_2 Документ_Тип3_Номер_2 01.01.2019 Вася 3 Документ_Тип1_Номер_3 Документ_Тип2_Номер_3 Документ_Тип3_Номер_3 02.01.2019 ВАСЯ 4 Документ_Тип1_Номер_2 Документ_Тип2_Номер_1 Документ_Тип3_Номер_2 02.01.2019 Петя 5 Документ_Тип1_Номер_3 Документ_Тип2_Номер_2 Документ_Тип3_Номер_3 02.01.2019 Петя 6 Документ_Тип1_Номер_2 Документ_Тип2_Номер_1 Документ_Тип3_Номер_2 03.01.2019 ВАСИЛИЙ 7 Документ_Тип1_Номер_3 Документ_Тип2_Номер_2 Документ_Тип3_Номер_2 03.01.2019 Таня 8 Документ_Тип1_Номер_3 Документ_Тип2_Номер_3 Документ_Тип3_Номер_2 03.01.2019 Таня 9 Документ_Тип1_Номер_2 Документ_Тип2_Номер_1 Документ_Тип3_Номер_3 03.01.2019 НИКОЛАЙ 10 Документ_Тип1_Номер_3 Документ_Тип2_Номер_2 Документ_Тип3_Номер_2 04.01.2019 Жора 11 Документ_Тип1_Номер_2 Документ_Тип2_Номер_3 Документ_Тип3_Номер_3 04.01.2019 Жора 12 Документ_Тип1_Номер_3 Документ_Тип2_Номер_1 Документ_Тип3_Номер_2 04.01.2019 Жора Из этой таблицы должны бать УДАЛЕНЫ строки 3,6,9 (или быраны без них) так как нету дублей по колонкам "Дата и Фамилия". В Колонках Док_х могут быть любые ссылки на документы, хоть на все одинаковые. | |||
| 45
    
        MetaDon 30.10.19✎ 16:36 | 
        сортировать не надо; начиная с конечной строки проходим вверх, сравниваем колонки, если дубля не нашли (дошли до 1) - конечную строку удаляем;)     | |||
| 46
    
        Креатив 30.10.19✎ 16:44 | 
        (45)Возможно ты и прав n*(n-1)/2 сравнений. При сортировке может оказаться больше.     | |||
| 47
    
        mistеr 30.10.19✎ 17:13 | 
        Решение без сортировки и без циклов по всей таблице.
 // Тестовые данные Запрос = Новый Запрос(" |ВЫБРАТЬ | ПриходныйКассовыйОрдер.Ссылка, | ПриходныйКассовыйОрдер.Организация, | ПриходныйКассовыйОрдер.Контрагент, | ПриходныйКассовыйОрдер.ДоговорКонтрагента, | ПриходныйКассовыйОрдер.СуммаДокумента |ИЗ | Документ.ПриходныйКассовыйОрдер КАК ПриходныйКассовыйОрдер |ГДЕ | ПриходныйКассовыйОрдер.Дата >= &НачалоПериода"); Запрос.УстановитьПараметр("НачалоПериода", НачалоГода(ТекущаяДата())); ТЗ = Запрос.Выполнить().Выгрузить(); // Начало алгоритма КлючевыеКолонки = "Контрагент,ДоговорКонтрагента"; КолонкаСчетчик = "_Строк"; ТЗПовторы = ТЗ.Скопировать(, КлючевыеКолонки); ТЗПовторы.Колонки.Добавить(КолонкаСчетчик); ТЗПовторы.ЗаполнитьЗначения(1, КолонкаСчетчик); ТЗПовторы.Свернуть(КлючевыеКолонки, КолонкаСчетчик); БезПовторов = ТЗПовторы.НайтиСтроки(Новый Структура(КолонкаСчетчик, 1)); СтркутураПоиска = Новый Структура(КлючевыеКолонки); Для Каждого Ключ Из БезПовторов Цикл ЗаполнитьЗначенияСвойств(СтркутураПоиска, Ключ); СтрокиКУдалению = ТЗ.НайтиСтроки(СтркутураПоиска); Для Каждого Строка Из СтрокиКУдалению Цикл ТЗ.Удалить(Строка); КонецЦикла; КонецЦикла; | |||
| 48
    
        mistеr 30.10.19✎ 17:15 | 
        Что-то с форматтером     | |||
| 49
    
        mistеr 30.10.19✎ 17:16 | 
        Да, забыл:
 ТЗ.Индексы.Добавить(КлючевыеКолонки); | |||
| 50
    
        MetaDon 30.10.19✎ 17:22 | 
        (46) конечно + еще убыстряем - вводим СЗ с номерами строк дублей,естественно их из проверки исключаем     | |||
| 51
    
        pechkin 30.10.19✎ 17:24 | 
        (46) это ты сортировку пузырьком взял     | |||
| 52
    
        new_hope 30.10.19✎ 17:33 | 
        (47) Уххх.. работает мгновенно на примерно 10-ти тысячах строк. Правда не проверял, насколько правдиво работает. Но наглядный результат - вроде как все верно!     | |||
| 53
    
        new_hope 30.10.19✎ 17:50 | 
        (47) Супер! Благодарю! То что надо!     | |||
| 54
    
        Garykom гуру 30.10.19✎ 18:20 | 
        (52) Удаление строк из ТЗ обычно медленней чем перенос только нужных строк в новую ТЗ.
 Так что перепиши на другие алгоритмы и протести | |||
| 55
    
        Сияющий в темноте 30.10.19✎ 18:43 | 
        (54)зависит от количества строк и количества колонок.     | |||
| 56
    
        Garykom гуру 30.10.19✎ 18:53 | 
        (55) В платформе 1С удаление строки в ТЗ вызывает создание новой ТЗ с переносом туда строк.
 Это так к сведению. | |||
| 57
    
        mistеr 30.10.19✎ 19:41 | 
        (56) Интересно. Есть подтверждения этому?     | |||
| 58
    
        mistеr 30.10.19✎ 19:43 | 
        (54) Судя по описанию ТС, в его случае удаляемых строк будет немного. Если много, то согласен, лучше формировать новую ТЗ.     | |||
| 59
    
        Garykom гуру 30.10.19✎ 19:45 | 
        (57) Несколько раз было уже тут на форуме     | |||
| 60
    
        mistеr 30.10.19✎ 19:52 | 
        (59) Не встречал. Это были пруфы или предположения?     | |||
| 61
    
        H A D G E H O G s 30.10.19✎ 21:47 | 
        (3) Как ни очевидно, что за такие решения надо бить по почкам.     | |||
| 62
    
        H A D G E H O G s 30.10.19✎ 21:47 | 
        (60) Это эротические фантазии.     | |||
| 63
    
        Garykom гуру 30.10.19✎ 22:10 | 
        (62) Это подтверждение или опровержение?
 Вроде бы провалами в памяти еще не страдаю, тестил кто то засекая время и пробуя удалять строки и копировать ТЗ. | |||
| 64
    
        Garykom гуру 30.10.19✎ 22:13 | 
        (61) В случае файловой базы это (запросом именно подобная задача) быстрее и проще, в случае отдельного sql сервера надо знать что будет делать сервер 1С, может он не будет передавать ему всю тз а сам на своем движке запрос выполнит.
 Я если честно хз но свой движок запросов у сервера 1С точно есть. | |||
| 65
    
        АнализДанных 30.10.19✎ 22:37 | 
        (47) (52) Ещё можно к таблице индексы добавить, тогда ещё быстрее поиск будет:
 Для Каждого ИмяКолонки Из СтрРазделить(КлючевыеКолонки, ",") Цикл ТЗ.Индексы.Добавить(ИмяКолонки); КонецЦикла; | |||
| 66
    
        mistеr 31.10.19✎ 08:56 | 
        (65) См. (49)     | |||
| 67
    
        new_hope 31.10.19✎ 10:30 | 
        Спасибо всем. Свою задачу я решил. Спасибо "mister"
 Но - очень интересно реализовать это чисто ЗАПРОСом. Буду благодарен, если кто-то предоставит готовый запрос по подобной таблице. (для самообразования) | |||
| 68
    
        catena 31.10.19✎ 10:39 | 
        (67) такое, чтоли?
 ВЫБРАТЬ п.Контрагент,п.ДоговорКонтрагента Договор,п.Ссылка,п.ДокументОснование,п.ВидОперации поместить тз ИЗ Документ.ПлатежноеПоручениеИсходящее КАК п; Выбрать п.Контрагент,п.Договор,Количество(п.Ссылка) поместить тз2 из тз п сгруппировать по п.Контрагент,п.Договор имеющие Количество(п.Ссылка)>1; Выбрать п.Контрагент,п.Договор,п.Ссылка,п.ДокументОснование,п.ВидОперации из тз п внутреннее соединение тз2 пп по п.Контрагент=пп.Контрагент и п.Договор=пп.Договор | |||
| 69
    
        rphosts 31.10.19✎ 10:42 | 
        (0) 1.Свернуть
 2.Запросом 3.Отсортировать и программно. проще всего №1, быстрее всего №2, середнячок №3. | 
 
 | Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |