SQL - 查找列中具有相同值集的行

时间:2015-10-27 17:07:34

标签: sql oracle

我有一个表,我希望选择所有具有与列中显示的完全相同的值集的行,并将它们作为一对特定列返回。

例如,假设我有一个名为Table的表:

C1  C2  
1   1  
1   2  
1   3  
2   1  
3   1  
3   2  
3   3  
4   1  
4   2  

当我运行查询时,它应该返回行:

1  3

因为这些是C1中的两个值,它们在C2(1,2,3)列中具有相同的值集。

我在下面有一个不正确的查询,它返回C2中至少有一个匹配值的所有行,我无法弄清楚如何纠正它。

SELECT DISTINCT T1.C1, T2.C1
FROM Table T1, Table T2
WHERE T1.C1 != T2.C1 
AND T1.C2 = T2.C2
AND T1.C1 < T2.C1
GROUP BY s1.suppId, s2.suppId;  

非常感谢任何帮助,谢谢。

3 个答案:

答案 0 :(得分:1)

listagg 是救援(而不是被@Juan评论)

 with lst as (
 select c1, LISTAGG(c2, '; ') WITHIN GROUP (ORDER BY c2) c2_lst
 from tst
 group by c1
 )
 select  lst1.c1 c1a, lst2.c1 c1b
 from lst lst1
 inner join lst lst2
 on lst1.c2_lst = lst2.c2_lst and
 lst1.c1 < lst2.c1
 ; 

按要求提供

1 3

<强> SQLFiddleDemo

同样要做好准备,这只能处理小数据(连接密钥限制为4000字节)。

<强> 更新

listagg连接组中的所有值。要仅获取不同的值(即值集),必须执行使用 DISTINCT 的其他查询。

 WITH lst AS
   ( SELECT DISTINCT c1,c2 FROM tst
   ),
   lst_dist AS
   (SELECT c1,
     LISTAGG(c2, '; ') WITHIN GROUP (
   ORDER BY c2) c2_lst
   FROM lst
   GROUP BY c1
   )
 SELECT lst1.c1 c1a,
   lst2.c1 c1b
 FROM lst_dist lst1
 INNER JOIN lst_dist lst2
 ON lst1.c2_lst = lst2.c2_lst
 AND lst1.c1    < lst2.c1

答案 1 :(得分:1)

正如您未指定的那样,这个将处理两组匹配的C2值的情况,输出两行 - 每个匹配集一个。

with thetable as (    
SELECT   1 C1,  1 c2 from dual union 
SELECT   1 C1,   2   c2 from dual union
SELECT   1 C1,   3   c2 from dual union
SELECT   2 C1,   1   c2 from dual union
SELECT   3 C1,   1   c2 from dual union
SELECT   3 C1,   2   c2 from dual union
SELECT   3 C1,   3   c2 from dual union
SELECT   4 C1,   1   c2 from dual union
SELECT   4 C1,   2  c2 from dual union
-- added fourrows to give a second set of matches
SELECT   5 C1,   1   c2 from dual union
SELECT   5 C1,   2  c2 from dual union
SELECT   6 C1,   1  c2 from dual union
SELECT   6 C1,   2  c2 from dual )
SELECT LIST_C2, List_c1
FROM (
    SELECT list_c2
          ,LISTAGG(c1,',') WITHIN GROUP (ORDER BY c1) list_c1
    FROM (      
            SELECT c1, LISTAGG(c2,',') WITHIN GROUP (ORDER BY c2) list_c2 
            FROM thetable
            GROUP BY c1
         )
    group by list_c2        
    )
-- only bring back where we had more than one c1
WHERE instr(list_c1,',') != 0

显示以下两组C2值及其C1匹配列表

LIST_C2  LIST_C1
"1,2"    "4,5,6"
"1,2,3"  "1,3"

答案 2 :(得分:1)

您可以使用自联接来执行此操作而不使用列表聚合:

select t1.c1, t2.c1
from (select t.*, count(*) over (partition by c1) as cnt
      from table t
     ) t1 join
     (select t.*, count(*) over (partition by c1) as cnt
      from table t
     ) t2
     on t1.c2 = t2.c2 and t1.c1 < t1.c2 and t1.cnt = t2.cnt
group by t1.c1, t2.c1
having count(*) = max(t1.cnt);

注意:这假定表中没有重复的行。在这种情况下,轻微的变化也可以起作用。

这会加入 second 列上的行,然后按第一行聚合。在此过程中,它确保两个表中匹配列的数量相同,并且所有列都匹配。

相关问题