Имя: Пароль:
1C
1С v8
Поиск (и удаление) не повторяющихся значений в таблице...
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.