Вход | Регистрация
 
1С:Предприятие :: 1С:Предприятие 8 общая

Поиск (и удаление) не повторяющихся значений в таблице...

Поиск (и удаление) не повторяющихся значений в таблице...
Я
   new_hope
 
30.10.19 - 15:16
Прошу, может кто знает действующий (и быстрый :-) алгоритм. Задача - ОСТАВИТЬ таблице (значений) те строки, которые повторяются два и более раз (то-есть удалить те строки, у которых нет повторов).
Поиск нужно осуществлять по 2-м колонкам из множества колонок.
 
 
   Beduin
 
1 - 30.10.19 - 15:17
Свернуть
   vicof
 
2 - 30.10.19 - 15:20
Формировать таблицу изначально нужно правильно, чтобы потом не заниматься всякой фигней
   Garykom
 
3 - 30.10.19 - 15:24
(0) Как это ни странно но данная задача лучше всего решается через запросы
   Garykom
 
4 - 30.10.19 - 15:25
(3)+ Засовываешь ТЗ в запрос и соединяешь с собой внутренним соединением по нужным колонкам.
Причем чтобы исключить дубли (строка сама с собой) добавить условие на номер строки например.
   new_hope
 
5 - 30.10.19 - 15:27
(2) (3) Пытался разобраться через ЗАПРОС - но у меня из 4-х колонок в 3-х колонках ссылки не смог разобраться, так как ссылки не группируются. Короче - недостаточно знаний. Если есть готовый пример - ткните ссылку. Спасибо.
   new_hope
 
6 - 30.10.19 - 15:29
(4) Мне дубли как раз нужно ВКЛЮЧАТЬ а не исключать. То что НЕ дублируется - вообще удалить (игнорировать) в результате
   Garykom
 
7 - 30.10.19 - 15:31
(6) У меня все правильно написано, именно только дубли и выберутся в результате запроса.
   vicof
 
8 - 30.10.19 - 15:36
(0) Зачем ты это хочешь сделать?
   new_hope
 
9 - 30.10.19 - 15:40
(8) т.к. это ошибочные значения и нужно знать о них и перейти по наборам ссылок этих значений
   Йохохо
 
10 - 30.10.19 - 15:42
(9) ну и бахни, НайтиСтроки, давно не удаляли строк из ТЗ
   azernot
 
11 - 30.10.19 - 15:48
Выбрать КОлонка1, Колонка2, 1 как КоличествоСтрок
Поместить ЗначенияКолонок
Из ТЗ
;

Выбрать
КОлонка1,
Колонка2,
Сумма(КОличествоСтрок)
Поместить ПовторяющиесяКлючевыеКолонки
Из ЗначенияКолонок
Сгрупппировать по
КОлонка1,
Колонка2
Имеющие Сумма(КОличествоСтрок)>1
;

Выбрать
*
из ТЗ
Внутреннее соединение ПовторяющиесяКлючевыеКолонки по ТЗ.Колонка1=  ПовторяющиесяКлючевыеКолонки.Колонка1 И ТЗ.Колонка2= ПовторяющиесяКлючевыеКолонки.Колонка2
   new_hope
 
12 - 30.10.19 - 15:49
(10) Так и думаю. Боюсь за скорость. Уверен, это можно сделать изящно запросом, но ума не хватает. :-(

Есть колонки "Документ1Ссылка, Документ2Ссылка, Документ3Ссылка, Дата, Фамилия" 

Так вот, нужно в результате оставить все значения, которые ИМЕЮТ дубли по полям "Дата и Фамилия". и дата и номер - значения НЕ уникальные.
   Йохохо
 
13 - 30.10.19 - 15:49
(11) а типизировать?)
   pechkin
 
14 - 30.10.19 - 15:50
можно без запроса. в 1 проход. просто проверять, что след строка не такая же и пред была не такая.
значит эта строка единственная.
тз вначале нужно отсортировать
   pechkin
 
15 - 30.10.19 - 15:51
ну или след строка такая же - добавляем строу в новую тз
   azernot
 
16 - 30.10.19 - 15:54
(13) В запросе можно использовать только ТЗ с типизованными колонками. Так что ничего типизировать не надо. Или я не понимаю о чём ты...
   mistеr
 
17 - 30.10.19 - 15:55
Сомневаюсь, что запросом всегда будет быстрее. Я бы сделал через Свернуть() и НайтиСтроки().
   Garykom
 
18 - 30.10.19 - 15:57
(14) (15) Слегка подумай, надо выбрать все строки (со всеми их колонками) имеющие дубли по двум колонкам.
Условие выбора задолбаешься придумывать, в отличие от запроса.

Тебе же надо выбрать и когда 2 и когда 3 и когда 4 строки и т.д. подряд имеют те же значения в паре колонок. Причем не пропустить и не накопировать лишнего в новую ТЗ.
   D_E_S_131
 
19 - 30.10.19 - 15:57
(12) Кинул свою ТЗ в запрос во временную таблицу. Соединил саму с собой по нужным полям (Дата и Фамилия). Поставил условие на поле из "дублирующей таблицы" "Есть НЕ Null".
   Garykom
 
20 - 30.10.19 - 15:58
(17) А вот это уже более разумный вариант но тормозной, так как сначала свертка а потом поиск в цикле по свернутым.
   Garykom
 
21 - 30.10.19 - 15:58
(19) см (4)
   azernot
 
22 - 30.10.19 - 16:00
(19) Такой план всегда будет возвращать всю исходную ТЗ. :)
   Garykom
 
23 - 30.10.19 - 16:00
(0) ТС выложи плиз тестовую табличку если не секретно, кому интересно на разных методах сможет потестить скорость.
   Garykom
 
24 - 30.10.19 - 16:00
(22) Угу условие забыл исключения пар строк с самой собой, я предложил по номеру строки условие
   azernot
 
25 - 30.10.19 - 16:00
+(22) нужно какое-то поле, позволяющие различать строки.. Типа "НомерСтроки". И ставить условие соединения по неравенству этого поля.
   mistеr
 
26 - 30.10.19 - 16:07
(20) Не очевидно, что тормозной. На малых объемах не ощутимо, а на больших хз, нужно тестировать. Данные не гоняются на скуль и обратно, индексирование может помочь, в общем не очевидно.
   pechkin
 
27 - 30.10.19 - 16:12
(18) ничего сложного нет.
классическая задача на именно программирование
   Garykom
 
28 - 30.10.19 - 16:12
(26) Проще тогда отсортировать, затем одним циклом проверять пары строк и находить начало и конец блока дубля строк.
Ну и имея эти пары НачальнаяСтрока, КонечнаяСтрока получить эти строки.
или вариация с накопителем, куда строки в цикле добавляются если равна следующая или если следующая строка не равна то если в накопителе >=2 строки их в новую ТЗ добавляем, а накопитель очищаем и т.д.
   pechkin
 
29 - 30.10.19 - 16:14
(28) ну тоже самое описал, про что я говорил в (15)
   azernot
 
30 - 30.10.19 - 16:14
(17) Зачем сворачивать?

Можно сделать в один цикл по ТЗ, с последующим удалением лишних
МасивСтрокКУдалению = Новый Массив();

ТЗКлючевыхПолей = Новый ТаблицаЗначений;
ТЗКлючевыхПолей.Колонки.Добавить("Колонка1", ТЗ.Колонки.найти("КОлонка1").ТипЗначения);
ТЗКлючевыхПолей.Колонки.Добавить("Колонка2", ТЗ.Колонки.найти("КОлонка2").ТипЗначения);
ТЗКлючевыхПолей.Колонки.Добавить("ПерваяСтрокаТЗ");

Для каждого СтрокаТЗ из ТЗ Цикл
    
    НайденныеСтроки = ТЗКлючевыхПолей.НайтиСтроки(Новый Структура("Колонка1, Колонка2", СтрокаТЗ.Колонка1, СтрокаТЗ.Колонка2);
    
    Если НайденныеСтроки.Количество()>0 ТОгда
        //Такие значения полей ранее уже встречались

        ИндексСтроки = МасивСтрокКУдалению.Найти(НайденныеСтроки[0].ПерваяСтрокаТЗ);
        Если НЕ ИндексСтроки = Неопределено ТОгда
            //Если первая строка с такими ключевыми полями числится к удалению, нужно убрать её оттуда

            МасивСтрокКУдалению.Удалить(ИндексСтроки);
        КонецЕсли;
        Продолжить;
    КОнецЕсли;
    
    //Сюда попадает только строка с ранее не встречающющимися значениями ключевых полей

    НоваяСтрокаКЛючевыхПолей = ТЗКлючевыхПОлей.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрокаКЛючевыхПолей, СтрокаТЗ);
    НоваяСтрокаКЛючевыхПолей.ПерваяСтрокаТЗ = СтрокаТЗ;
    МасивСтрокКУдалению.Добавить(СтрокаТЗ);
КонецЦикла;

Для каждого УдаляемаяСтрока Из МасивСтрокКУдалению Цикл
    ТЗ.Удалить(УдаляемаяСтрока);
КонецЦикла;
 
 Рекламное место пустует
   Garykom
 
31 - 30.10.19 - 16:16
(29) Ты упустил важную вещь про буфер, твой алгоритм правильно только для пар дубль строк а если их там триплеты и более не сработает.
   pechkin
 
32 - 30.10.19 - 16:16
(31) почему? достаточно счетчик добавить. буфер не нужен
   Garykom
 
33 - 30.10.19 - 16:16
(30) Запросом сильно короче выглядит чем вот это длинное
   Garykom
 
34 - 30.10.19 - 16:17
(32) Два счетчика тогда
   azernot
 
35 - 30.10.19 - 16:18
(33) Зато без передачи данных с сервера приложений на сервер баз данных и наоборот.
   pechkin
 
36 - 30.10.19 - 16:19
(34) не нужно.
предыдущую строку добавляем.если они совпадает с текущей.
текущую добавляем, если счетчик > 1
при смене строки сбарсываем счетчик
   azernot
 
37 - 30.10.19 - 16:19
+(35) Хотя, может я неверно понимаю механизм запросов и в данном случае он не будет обращаться к серверу баз данных. Но почему-то я думаю, что это не так.
   mistеr
 
38 - 30.10.19 - 16:23
(30) Сворачивать для того, чтобы не делать циклы по всей ТЗ.
   new_hope
 
39 - 30.10.19 - 16:23
(23) А как выложить? Это не типовая конфа и как мне ссылки на документы выложить? Саму структуру таблички я указал (в реальной жизни вместо "Фамилия" - Строка с буквенно-цифровым значением :-)
   Ёпрст
 
40 - 30.10.19 - 16:24
(30) можно сделать еще проще, достаточно отсортировать тз по ключевым полям и дальше сравнение строк с предыдущей.
Тогда НайтиСтроки в цикле не надо делать
   Garykom
 
41 - 30.10.19 - 16:27
(39) Табличку екселя или csv файлик с данными колонок можно выкладывать
   Garykom
 
42 - 30.10.19 - 16:28
(40) Угу см (28)
   Креатив
 
43 - 30.10.19 - 16:34
Присоединяюсь к тем ораторам, что за сортировку по ключевым полям и последующее сравнение строк.
Единственно добавлю, что обход нужно делать снизу таблицы, чтобы при удалении строк что-нибудь не пошло не так. Не факт, что будет быстро, зато очень прозрачно.
   new_hope
 
44 - 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 (или быраны без них) так как нету дублей по колонкам "Дата и Фамилия". В Колонках Док_х могут быть любые ссылки на документы, хоть на все одинаковые.
   MetaDon
 
45 - 30.10.19 - 16:36
сортировать не надо; начиная с конечной строки проходим вверх, сравниваем колонки, если дубля не нашли (дошли до 1) - конечную строку удаляем;)
   Креатив
 
46 - 30.10.19 - 16:44
(45)Возможно ты и прав n*(n-1)/2 сравнений. При сортировке может оказаться больше.
   mistеr
 
47 - 30.10.19 - 17:13
Решение без сортировки и без циклов по всей таблице.


    // Тестовые данные

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

    // Начало алгоритма

    КлючевыеКолонки = "Контрагент,ДоговорКонтрагента";
    КолонкаСчетчик = "_Строк";

    ТЗПовторы = ТЗ.Скопировать(, КлючевыеКолонки);
    ТЗПовторы.Колонки.Добавить(КолонкаСчетчик);
    ТЗПовторы.ЗаполнитьЗначения(1, КолонкаСчетчик);
    ТЗПовторы.Свернуть(КлючевыеКолонки, КолонкаСчетчик);
    БезПовторов = ТЗПовторы.НайтиСтроки(Новый Структура(КолонкаСчетчик, 1));

    СтркутураПоиска = Новый Структура(КлючевыеКолонки);
    Для Каждого Ключ Из БезПовторов Цикл
        ЗаполнитьЗначенияСвойств(СтркутураПоиска, Ключ);
        СтрокиКУдалению = ТЗ.НайтиСтроки(СтркутураПоиска);
        Для Каждого Строка Из СтрокиКУдалению Цикл
            ТЗ.Удалить(Строка);
        КонецЦикла;
    КонецЦикла;
   mistеr
 
48 - 30.10.19 - 17:15
Что-то с форматтером
   mistеr
 
49 - 30.10.19 - 17:16
Да, забыл:

    ТЗ.Индексы.Добавить(КлючевыеКолонки);
   MetaDon
 
50 - 30.10.19 - 17:22
(46) конечно + еще убыстряем - вводим СЗ с номерами строк дублей,естественно их из проверки исключаем
   pechkin
 
51 - 30.10.19 - 17:24
(46) это ты сортировку пузырьком взял
   new_hope
 
52 - 30.10.19 - 17:33
(47) Уххх.. работает мгновенно на примерно 10-ти тысячах строк. Правда не проверял, насколько правдиво работает. Но наглядный результат - вроде как все верно!
   new_hope
 
53 - 30.10.19 - 17:50
(47) Супер! Благодарю! То что надо!
   Garykom
 
54 - 30.10.19 - 18:20
(52) Удаление строк из ТЗ обычно медленней чем перенос только нужных строк в новую ТЗ.
Так что перепиши на другие алгоритмы и протести
   Сияющий в темноте
 
55 - 30.10.19 - 18:43
(54)зависит от количества строк и количества колонок.
   Garykom
 
56 - 30.10.19 - 18:53
(55) В платформе 1С удаление строки в ТЗ вызывает создание новой ТЗ с переносом туда строк.
Это так к сведению.
   mistеr
 
57 - 30.10.19 - 19:41
(56) Интересно. Есть подтверждения этому?
   mistеr
 
58 - 30.10.19 - 19:43
(54) Судя по описанию ТС, в его случае удаляемых строк будет немного. Если много, то согласен, лучше формировать новую ТЗ.
   Garykom
 
59 - 30.10.19 - 19:45
(57) Несколько раз было уже тут на форуме
   mistеr
 
60 - 30.10.19 - 19:52
(59) Не встречал. Это были пруфы или предположения?
   H A D G E H O G s
 
61 - 30.10.19 - 21:47
(3) Как ни очевидно, что за такие решения надо бить по почкам.
   H A D G E H O G s
 
62 - 30.10.19 - 21:47
(60) Это эротические фантазии.
   Garykom
 
63 - 30.10.19 - 22:10
(62) Это подтверждение или опровержение?
Вроде бы провалами в памяти еще не страдаю, тестил кто то засекая время и пробуя удалять строки и копировать ТЗ.
   Garykom
 
64 - 30.10.19 - 22:13
(61) В случае файловой базы это (запросом именно подобная задача) быстрее и проще, в случае отдельного sql сервера надо знать что будет делать сервер 1С, может он не будет передавать ему всю тз а сам на своем движке запрос выполнит.
Я если честно хз но свой движок запросов у сервера 1С точно есть.
   АнализДанных
 
65 - 30.10.19 - 22:37
(47) (52) Ещё можно к таблице индексы добавить, тогда ещё быстрее поиск будет:

Для Каждого ИмяКолонки Из СтрРазделить(КлючевыеКолонки, ",") Цикл
    ТЗ.Индексы.Добавить(ИмяКолонки);
КонецЦикла;
   mistеr
 
66 - 31.10.19 - 08:56
(65) См. (49)
 
 Рекламное место пустует
   new_hope
 
67 - 31.10.19 - 10:30
Спасибо всем. Свою задачу я решил. Спасибо "mister"
Но - очень интересно реализовать это чисто ЗАПРОСом. Буду благодарен, если кто-то предоставит готовый запрос по подобной таблице. (для самообразования)
   catena
 
68 - 31.10.19 - 10:39
(67) такое, чтоли?

ВЫБРАТЬ
    п.Контрагент,п.ДоговорКонтрагента Договор,п.Ссылка,п.ДокументОснование,п.ВидОперации поместить тз    
ИЗ Документ.ПлатежноеПоручениеИсходящее КАК п;
Выбрать п.Контрагент,п.Договор,Количество(п.Ссылка) поместить тз2 из тз п сгруппировать по п.Контрагент,п.Договор имеющие Количество(п.Ссылка)>1;
Выбрать 
    п.Контрагент,п.Договор,п.Ссылка,п.ДокументОснование,п.ВидОперации
из тз п внутреннее соединение тз2 пп по п.Контрагент=пп.Контрагент и п.Договор=пп.Договор
   rphosts
 
69 - 31.10.19 - 10:42
(0) 1.Свернуть
2.Запросом
3.Отсортировать и программно.

проще всего №1, быстрее всего №2, середнячок №3.


Список тем форума
Рекламное место пустует  Рекламное место пустует
Проблемы невозможно решaть нa том же уровне компетентности, нa котором они возникaют. Альберт Эйнштейн
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.