我有一个表,我希望选择所有具有与列中显示的完全相同的值集的行,并将它们作为一对特定列返回。
例如,假设我有一个名为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;
非常感谢任何帮助,谢谢。
答案 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 列上的行,然后按第一行聚合。在此过程中,它确保两个表中匹配列的数量相同,并且所有列都匹配。