Как сравнить группы кортежей в sql

Как сравнивать группы кортежей в sql: рассмотрим следующий пример:

TABLE T1
--------
GROUP     VALUE
-----     -----
A         FOO
A         BAR
X         HHH
X         ZOO

TABLE T2
--------
GROUP     VALUE
-----     -----
B         ZOO
C         FOO
C         BAR

Я хочу написать SQL-запрос, который сравнивает группы значений в обеих таблицах и сообщает о различиях. В проиллюстрированном примере группа в таблице a: ((A,FOO),(A,BAR)) совпадает с группой ((C,FOO),(C,BAR)) даже при том, что имя группы отличается . Важно, чтобы содержимое группы было одинаковым. Наконец, запрос сообщит, что есть разница: это кортеж (B, ZOO).

RESULT
------
GROUP     VALUE
-----     -----
B         ZOO
X         HHH
X         ZOO

Хотя группа X, содержащая ZOO в T1, имеет совпадающее значение в T2: (B, ZOO), это все еще не совпадение, поскольку группа также имеет значение (X, HHH), которое не является частью группы (B, ZOO). в Т2


person paweloque    schedule 03.12.2009    source источник
comment
Каким должен быть результат? Просто список групп, которые отличаются? Или сами отличия?   -  person Mark Byers    schedule 03.12.2009
comment
Вывод на самом деле не важен, важно то, что запрос видит группы и сравнивает их как группы.   -  person paweloque    schedule 03.12.2009
comment
Когда вы публикуете подобные вопросы, покажите нам образцы данных, примеры результатов, четко перечисленные и размеченные, чтобы мы могли легко вам помочь.   -  person JonH    schedule 03.12.2009
comment
Это произвольное количество значений в группе или всегда два?   -  person DCookie    schedule 04.12.2009
comment
это произвольное число   -  person paweloque    schedule 04.12.2009


Ответы (2)


Что-то вроде этого

create table t1 (group_id varchar2(20), value varchar2(20));
create table t2 (group_id varchar2(20), value varchar2(20));

insert into t1 values ('A','FOO');
insert into t1 values ('A','BAR');
insert into t1 values ('X','HHH');
insert into t1 values ('X','ZOO');
insert into t2 values ('C','FOO');
insert into t2 values ('C','BAR');
insert into t2 values ('B','ZOO');


select t1.group_id t1_group,t2.group_id t2_group, 
      --t1.all_val, t2.all_val, 
       case when t1.all_val = t2.all_val then 'match' else 'no match' end coll_match
from 
  (select 'T1' tab_id, group_id, collect(value) all_val, 
          min(value) min_val, max(value) max_val, count(distinct value) cnt_val 
  from t1 group by group_id) t1
full outer join
  (select 'T2' tab_id, group_id, collect(value) all_val, 
          min(value) min_val, max(value) max_val, count(distinct value) cnt_val 
  from t2 group by group_id) t2
on t1.min_val = t2.min_val and t1.max_val = t2.max_val and t1.cnt_val = t2.cnt_val
/

Я сделал предварительное исключение на основе минимального, максимального и количества различных значений в каждой группе, что помогло бы с большими наборами данных. Если наборы данных достаточно малы, они могут вам не понадобиться.

Это говорит вам совпадения. Вам просто нужно сделать дополнительный шаг, чтобы найти группы, в которых нет совпадений.

select t1_group
from
(
  select t1.group_id t1_group,t2.group_id t2_group, 
        --t1.all_val, t2.all_val, 
         case when t1.all_val = t2.all_val then 'match' end coll_match
  from 
    (select 'T1' tab_id, group_id, collect(value) all_val
    from t1 group by group_id) t1
  cross join
    (select 'T2' tab_id, group_id, collect(value) all_val
    from t2 group by group_id) t2
)
group by t1_group
having min(coll_match) is null
/

select t2_group
from
(
  select t1.group_id t1_group,t2.group_id t2_group, 
        --t1.all_val, t2.all_val, 
         case when t1.all_val = t2.all_val then 'match' end coll_match
  from 
    (select 'T1' tab_id, group_id, collect(value) all_val
    from t1 group by group_id) t1
  cross join
    (select 'T2' tab_id, group_id, collect(value) all_val
    from t2 group by group_id) t2
)
group by t2_group
having min(coll_match) is null
/
person Gary Myers    schedule 03.12.2009
comment
Я точно не понимаю, для чего вы используете значения min/max/count? - person paweloque; 04.12.2009
comment
Если у вас есть большой набор данных (десятки/сотни тысяч строк), сравнение каждой группы в таблице 1 с каждой группой в таблице 2 будет большой задачей. Мин./макс./количество сократит это до более удобного уровня, быстро исключив группы с разным количеством участников или с разными минимальными/максимальными значениями. - person Gary Myers; 04.12.2009
comment
Что делать, если значения min/max/count одинаковы для группы, но группы различаются? - person paweloque; 04.12.2009
comment
Пришлось внести некоторые изменения, т.е. я использую не min/max/count, а содержимое all_vall, но кроме того: ты лучший! Большое спасибо, ваш ответ был очень полезен! - person paweloque; 04.12.2009
comment
Я подожду, пока не смогу предложить вам 100 баллов в качестве награды. - person paweloque; 04.12.2009

Разница между T1 и T2 (две таблицы) может заключаться в следующем:

SELECT
   T1.GROUPNAME,
   T1.VALUE
FROM 
   T1
LEFT JOIN T2
ON T2.Value = T1.Value
WHERE T2.GROUPNAME IS NULL

Например, T1 имеет:

Фу 100 Бар 200 ЗЗЗ 333

И T2 включает в себя: Foo 100 Bar 200

Результатом этого запроса является ZZZ 333, это единственная запись, которая не совпадает в обеих таблицах. Вы даже можете изменить название группы T2, чтобы сказать:

XYZ 100 ZXZ 200

И результат по-прежнему ZZZ 333. Это то, о чем вы спрашиваете, если вы хотите наоборот, вы можете либо ОБЪЕДИНИТЬ его, либо использовать ПРАВОЕ соединение.

Джон

person JonH    schedule 03.12.2009
comment
На самом деле меня волнует, что значения в T2 являются частями одной и той же группы. - person paweloque; 03.12.2009
comment
Я не понимаю, что вы спрашиваете. Снова предоставьте DDL для всех ваших таблиц/схем. Предоставьте хорошие образцы данных и ожидаемые результаты. Что вы имеете в виду, что вас волнует, что значения в T2 являются частями одной и той же группы? Кто-то в комментариях спросил вас об именах групп, и вы сказали, что не имеет значения название группы, просто их значения совпадают в обеих таблицах. Мой запрос обрабатывает это. - person JonH; 03.12.2009