【问题标题】:How to compare groups of tuples in sql如何比较sql中的元组组
【发布时间】:2009-12-03 17:05:16
【问题描述】:

如何比较 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

尽管在 T1 中包含 ZOO 的组 X 在 T2 中有一个匹配值:(B,ZOO) 它仍然不是匹配,因为该组也有 (X, HHH) 值,它不属于 (B, ZOO) T2 组

【问题讨论】:

  • 输出应该是什么?只是不同组的列表?还是差异本身?
  • 输出并不重要,重要的是查询看到了组并将它们作为组进行比较。
  • 当您发布类似这样的问题时,请向我们展示示例数据,示例结果清楚地列出并标记,以便我们轻松帮助您。
  • 这是组中任意数量的值,还是总是两个?
  • 任意数字

标签: sql oracle comparison row-value-expression


【解决方案1】:

像这样的

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
/

【讨论】:

  • 我看不太清楚,你用最小/最大/计数值做什么?
  • 如果您有一个大型数据集(数十/数十万行),将 table1 中的每个组与 table2 中的每个组进行比较将是一项艰巨的任务。最小/最大/计数将通过快速排除具有不同成员数量或具有不同最小/最大值的组来将其降低到更易于管理的水平。
  • 如果一个组的 min / max / count 值相同,但组不同怎么办?
  • 我不得不做一些改变,即我不使用最小/最大/计数,而是使用 all_vall 的内容,但除此之外:你是最棒的!非常感谢,你的回答很有用!
  • 我会等到我能给你100分作为赏金。
【解决方案2】:

T1 和 T2(两张表)的区别可能是这样的:

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

例如 T1 有:

Foo 100 酒吧 200 ZZZ 333

T2 包括: 富 100 酒吧 200

该查询的结果是 ZZZ 333,它是两个表中唯一不匹配的记录。您甚至可以将 T2 的组名更改为:

XYZ 100 ZXZ 200

结果仍然是 ZZZ 333。这就是你所要求的,如果你想要相反的结果,你可以 UNION 到它,或者使用 RIGHT join。

乔恩

【讨论】:

  • 其实我关心的是 T2 中的值是同一组的一部分。
  • 我不明白你在问什么。再次为您的所有表/架构提供 DDL。提供良好的样本数据和预期的结果。你是什​​么意思你关心 T2 中的值是同一组的一部分? cmets 中有人问您有关组名的问题,您说组名无关紧要,只是它们的值在两个表中都匹配。我的查询处理。
猜你喜欢
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多