Создайте группы в таблице, если они имеют похожие наборы полей - PullRequest
0 голосов
/ 21 февраля 2020

У меня есть таблица

dept att1 
d1   a       
d2   a
d3   a
d3   c
d4   a
d4   b
d5   a
d5   b

Я хочу создать логические группы из приведенной выше таблицы следующим образом

group 1: d1,d2
group 2: d3
group 3: d4,d5

Я добавлю dept в логическую группу, если у них есть точные набор соответствует столбцу att1.

Например: d1 и d2 имеют общее значение, a.d3 имеет a, но также дополнительно содержит c .d4, а d5 имеет a и b, образуя отдельную группу. Как этого добиться, используя sql

Ответы [ 3 ]

2 голосов
/ 21 февраля 2020

В ответе Кирана используется правильный подход: объединить значения ATT1 по отделам, а затем сгруппировать по объединенным значениям. Проблема в том, что LISTAGG не может создать строку, длиннее VARCHAR2, и вы не можете GROUP BY строку, длиннее VARCHAR2.

. Чтобы преодолеть ограничение LISTAGG, используйте * 1008. *.

Чтобы преодолеть ограничение GROUP BY, сгруппируйте строку по ha sh, а не по самой строке. Существует очень и очень небольшая вероятность ложного срабатывания. Чтобы уменьшить вероятность этого, обновите базу данных до более новой версии, в которой используется больший га sh.

select listagg(dept,',') within group(order by dept) depts
from (
  select dept,
    dbms_crypto.hash(
      xmlagg(xmlelement("a", att1) order by att1).getClobVal(),
      3
    ) att1_hash
  from (select distinct dept, att1 from t)
  group by dept
)
group by att1_hash;
1 голос
/ 21 февраля 2020

Я думаю, что если вы используете oracle 11g R2, то нижеприведенное решение должно работать

SELECT Listagg(dept, ',') 
         within GROUP (ORDER BY dept) AS att 
FROM   (SELECT dept, 
               Listagg(att1, ',') 
                 within GROUP (ORDER BY att1) AS att 
        FROM   test 
        GROUP  BY dept)A 
GROUP  BY A.att 

, пожалуйста, см. sql fiddle demo

http://sqlfiddle.com/#! 4 / ddef3 / 5/0

0 голосов
/ 21 февраля 2020

Чтобы обойти пределы Oracle, вы можете идентифицировать все пары dept с одинаковыми атрибутами. Затем используйте имя минимального отдела (или рейтинг по нему) в качестве группы.

Предполагая, что пары уникальны, следующее генерирует совпадающие пары:

with dn as (
      select dept, attr, count(*) over (partition by dept) as cnt
      from t
     )
select dn1.dept, dn2.dept
from dn dn1 join
     dn dn2
     on dn2.att1 = dn1.att1 and
        dn2.cnt = dn1.cnt
group by dn1.dept, dn2.dept, dn1.cnt
having count(*) = dn1.cnt  -- all match

Обратите внимание, что это сохраняет ВСЕ пары с одинаковыми значениями att1, поэтому все dept соответствуют друг другу в этом результате.

Для окончательного назначения группы:

with dn as (
      select dept, attr, count(*) over (partition by dept) as cnt
      from t
     )
select dept1, min(dept2) as first_dept,
       dense_rank() over (order by min(dept2)) as grp_number
from (select dn1.dept as dept1, dn2.dept as dept2
      from dn dn1 join
           dn dn2
           on dn2.att1 = dn1.att1 and
              dn2.cnt = dn1.cnt
      group by dn1.dept, dn2.dept, dn1.cnt
      having count(*) = dn1.cnt
     ) dd
group by dept1;

В общем, я предпочитаю listagg() подход. Но если это невозможно, это также должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...