Вход | Регистрация
 
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.


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