Найти дубликат в таблице

122
17

У меня есть таблица, содержащая дубликат. Способ идентификации дубликата - ключ должен находиться в одной и той же группе (1,2,3 или 4) - p должен быть одинаковым - P - это идентификатор, который говорит, что эти ключи одинаковы. Ключ может совпадать несколько раз в той же группе.

Скажем, у нас есть этот пример ниже:

key,p,group
1,1,1
33,1,1
5,1,1
5,2,1
4,2,1
4,15,1
8,4,1
10,5,1
15,6,1
21,15,1
78,7,1
79,8,2
80,8,2
81,9,3
82,9,3
85,10,4
90,11,1
91,11,1
73,12,1

Выход должен быть:

key,p,group
1,999,1
5,999,1
4,999,1
21,999,1
33,999,1
8,4,1
10,5,1
15,6,1
78,7,1
79,111,2
80,111,2
81,666,3
82,666,3
85,10,4
90,222,1
91,222,1
73,12,1

1,5,4,21 и 33 имеют одинаковое значение для p (999, это число является просто новым идентификатором для группировки дубликата вместе), поскольку они находятся в одной группе (группа = 1) и 1,5 и 33 совпадение (p = 1), совпадение 5 и 4 (p = 2), совпадение 4 и 21 (p = 15)

Для 90,91 даже они находятся в группе 1, они совпадают только потому, что они не связаны (крест) с другим ключом в этой группе.

79 и 80 находятся в одной группе (группа = 2)

8 держите p = 4, потому что он не совпадает с другими клавишами в группе = 1.

и так далее... Я ищу способ сделать это в SQL (Oracle) или алгоритме...

На самом деле, он не работает. Если у вас есть это на входе:

key,p,group
55,9,6
56,10,6
56,11,6
58,9,6
58,11,6

Выход будет

key,p,group
55,9,6
56,9,6
58,9,6
56,10,6
58,10,6

или мне нужно:

key,p,group
55,9,6
56,9,6
58,9,6
56,9,6
58,9,6

Спасибо за помощь

спросил(а) 2021-01-19T20:24:04+03:00 9 месяцев, 1 неделя назад
1
Решение
65

Если я правильно понял проблему: просмотрите строки как узлы (неориентированного) графа, с ребрами, соединяющими узлы, если они имеют одинаковые значения p и группы или одни и те же значения ключа и группы. Затем найдите подключенные компоненты этого графика и измените значение p так, чтобы все узлы в компоненте связи имели одинаковое значение p.

Если это так, это можно сделать с помощью иерархического запроса (плюс вся обработка, необходимая до и после нее, основная часть - иерархический запрос). В приведенном ниже решении я изменяю все значения p в подключенном компоненте на MIN значений p в группе (а не на случайное значение); если желательны "случайные значения", которые могут быть выполнены тоже, но это другой вопрос с гораздо более простым решением (и, возможно, не требуется в первую очередь).

GROUP не является хорошим именем столбца, поскольку это зарезервированное слово в Oracle. Я изменил его на GRP.

with
-- begin test data (this is not part of the solution)
inputs ( key, p, grp ) as (
select 1, 1, 1 from dual union all
select 33, 1, 1 from dual union all
select 5, 1, 1 from dual union all
select 5, 2, 1 from dual union all
select 4, 2, 1 from dual union all
select 4, 15, 1 from dual union all
select 8, 4, 1 from dual union all
select 10, 5, 1 from dual union all
select 15, 6, 1 from dual union all
select 21, 15, 1 from dual union all
select 78, 7, 1 from dual union all
select 79, 8, 2 from dual union all
select 80, 8, 2 from dual union all
select 81, 9, 3 from dual union all
select 82, 9, 3 from dual union all
select 85, 10, 4 from dual union all
select 90, 11, 1 from dual union all
select 91, 11, 1 from dual union all
select 73, 12, 1 from dual union all
select 55, 9, 6 from dual union all
select 56, 10, 6 from dual union all
select 56, 11, 6 from dual union all
select 58, 9, 6 from dual union all
select 58, 11, 6 from dual
),
-- end of test data; solution (SQL query) continues below this line
prep ( grp, parent, child ) as (
select distinct a.grp, a.p, b.p
from inputs a inner join inputs b
on a.grp = b.grp and a.key = b.key
),
h ( grp, rt, child ) as (
select grp, connect_by_root parent, child
from prep
connect by nocycle grp = prior grp and parent = prior child
)
select distinct i.key, g.new_p as p, i.grp
from inputs i join (
select grp, rt, min(child) as new_p
from h
group by grp, rt
) g
on g.grp = i.grp and g.rt = i.p
order by grp, p, key -- optional
;

Выход:

       KEY          P        GRP
---------- ---------- ----------
1 1 1
4 1 1
5 1 1
21 1 1
33 1 1
8 4 1
10 5 1
15 6 1
78 7 1
90 11 1
91 11 1
73 12 1
79 8 2
80 8 2
81 9 3
82 9 3
85 10 4
55 9 6
56 9 6
58 9 6

20 rows selected.

ответил(а) 2021-01-19T20:24:04+03:00 9 месяцев, 1 неделя назад
47

select KEY, 
P,
GRP,
'group of '||count(*) over (partition by p,grp)||' with p value '||p
from key_table

Вывод:


1   1   1   group of 3 with p value 1
33 1 1 group of 3 with p value 1
5 1 1 group of 3 with p value 1
5 2 1 group of 2 with p value 2
4 2 1 group of 2 with p value 2
8 4 1 group of 1 with p value 4
10 5 1 group of 1 with p value 5
15 6 1 group of 1 with p value 6
78 7 1 group of 1 with p value 7
79 8 2 group of 2 with p value 8
80 8 2 group of 2 with p value 8
81 9 3 group of 2 with p value 9
82 9 3 group of 2 with p value 9
85 10 4 group of 1 with p value 10
91 11 1 group of 2 with p value 11
90 11 1 group of 2 with p value 11
73 12 1 group of 1 with p value 12
4 15 1 group of 2 with p value 15
21 15 1 group of 2 with p value 15

Я не слишком увлечен случайными значениями, но изменяю функцию вывода, как вам нравится.

ответил(а) 2021-01-19T20:24:04+03:00 9 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема