在 Oracle 中使用聚合加入
Joins using aggregation in Oracle
我有两个 table。 Table 主要和次要。我需要加入这两个 table。具有相同 grp_id 的键是一组。例如:在 Table 中,main (BWA,ST,FD62E015) 是一组,(BWA,VI,FD62E015) 是另一组,依此类推。另一个 table sub 也是如此。现在我想加入这两个 tables 并从主 table 获取 grp_id,如果组在 table 子中有密钥(BWA,FD62E015)从 Main table 获取 grp_id 1 和 2 并且具有密钥 (BWA,FM62Q011) 的组获取 grp_id 3 和 4.
所以正常的连接在这里不起作用,因为子 table 中的两个组都有密钥 BWA。有没有办法聚合密钥并加入它们?
Table : Main
Std_id Grp_id Key
1234 1 BWA
1234 1 ST
1234 1 FD62E015
1234 2 BWA
1234 2 VI
1234 2 FD62E015
1234 3 BWA
1234 3 ST
1234 3 FM62Q011
1234 4 BWA
1234 4 VI
1234 4 FM62Q011
Table : Sub
Std_id Grp_id Key
1234 1 BWA
1234 1 FD62E015
1234 2 BWA
1234 2 FM62Q011
期望的结果:
Std_id sub.Grp_id main.grp_id sub.Key
1234 1 1 BWA
1234 1 1 FD62E015
1234 1 2 BWA
1234 1 2 FD62E015
1234 2 3 BWA
1234 2 3 FM62Q011
1234 2 4 BWA
1234 2 4 FM62Q011
选项 1:
SELECT std_id,
grp_id,
key
FROM (
SELECT m.*,
COUNT(DISTINCT m.key) OVER (PARTITION BY m.std_id, m.grp_id) AS num_keys
FROM main m
INNER JOIN sub s
ON ( m.std_id = s.std_id
AND CEIL(m.grp_id/2) = s.grp_id -- or some other way of mapping the grp_ids
AND m.key = s.key)
)
WHERE num_keys = 2;
选项 2:
您可以创建一个 user-defined 集合类型:
CREATE TYPE string_list AS TABLE OF VARCHAR2(20);
然后使用:
SELECT m.std_id,
m.grp_id,
m.key
FROM (SELECT m.*,
CAST(
COLLECT(key) OVER(PARTITION BY std_id, grp_id)
AS string_list
) AS keys
FROM main m
) m
INNER JOIN
(SELECT s.*,
CAST(
COLLECT(key) OVER(PARTITION BY std_id, grp_id)
AS string_list
) AS keys
FROM sub s
) s
ON ( m.std_id = s.std_id
AND CEIL(m.grp_id/2) = s.grp_id -- or some other way of mapping the grp_ids
AND m.key = s.key
AND CARDINALITY(m.keys MULTISET INTERSECT DISTINCT s.keys) >= 2
)
其中,对于示例数据:
CREATE TABLE main (Std_id, Grp_id, Key) AS
SELECT 1234, 1, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 1, 'ST' FROM DUAL UNION ALL
SELECT 1234, 1, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 2, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 2, 'VI' FROM DUAL UNION ALL
SELECT 1234, 2, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 3, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 3, 'ST' FROM DUAL UNION ALL
SELECT 1234, 3, 'FM62Q011' FROM DUAL UNION ALL
SELECT 1234, 4, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 4, 'VI' FROM DUAL UNION ALL
SELECT 1234, 4, 'FM62Q011' FROM DUAL;
CREATE TABLE Sub (Std_id, Grp_id, Key) AS
SELECT 1234, 1, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 1, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 2, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 2, 'FM62Q011' FROM DUAL;
双输出:
STD_ID
GRP_ID
KEY
1234
1
BWA
1234
1
FD62E015
1234
2
BWA
1234
2
FD62E015
1234
3
BWA
1234
3
FM62Q011
1234
4
BWA
1234
4
FM62Q011
db<>fiddle here
发布所需结果后,看看是否有帮助。
SQL> with
2 tmain as
3 (select std_id, grp_id, listagg(key, ',') within group (order by key) keys
4 from main
5 where (std_id, key) in (select std_id, key from sub)
6 group by std_id, grp_id
7 ),
8 tsub as
9 (select std_id, grp_id, listagg(key, ',') within group (order by key) keys
10 from sub
11 group by std_id, grp_id
12 )
13 select s.std_id, s.grp_id, tm.grp_id main_grp_id, s.key
14 from sub s join tsub ts on ts.std_id = s.std_id and ts.grp_id = s.grp_id
15 join tmain tm on tm.std_id = ts.std_id and tm.keys = ts.keys
16 order by s.std_id, s.grp_id, tm.grp_id, s.key;
STD_ID GRP_ID MAIN_GRP_ID KEY
---------- ---------- ----------- --------
1234 1 1 BWA
1234 1 1 FD62E015
1234 1 2 BWA
1234 1 2 FD62E015
1234 2 3 BWA
1234 2 3 FM62Q011
1234 2 4 BWA
1234 2 4 FM62Q011
8 rows selected.
SQL>
tmain
和 tsub
CTE 生成 新密钥(使用 listagg
函数)
- 然后在“主”
select
语句中使用这些新键来连接那些 table(连同“原始”sub
table,到获取您需要的其他值
使用 [NOT] EXISTS
select *
from main m
where EXISTS (
select 1
from (select distinct Grp_id from Sub) s
where NOT EXISTS (
select 1
from Sub s2
where s2.Grp_id = s.Grp_id and NOT EXISTS (
select 1
from main m2
where m2.Grp_id = m.Grp_id and s2.Key = m2.Key
)
)
);
我有两个 table。 Table 主要和次要。我需要加入这两个 table。具有相同 grp_id 的键是一组。例如:在 Table 中,main (BWA,ST,FD62E015) 是一组,(BWA,VI,FD62E015) 是另一组,依此类推。另一个 table sub 也是如此。现在我想加入这两个 tables 并从主 table 获取 grp_id,如果组在 table 子中有密钥(BWA,FD62E015)从 Main table 获取 grp_id 1 和 2 并且具有密钥 (BWA,FM62Q011) 的组获取 grp_id 3 和 4.
所以正常的连接在这里不起作用,因为子 table 中的两个组都有密钥 BWA。有没有办法聚合密钥并加入它们?
Table : Main
Std_id Grp_id Key
1234 1 BWA
1234 1 ST
1234 1 FD62E015
1234 2 BWA
1234 2 VI
1234 2 FD62E015
1234 3 BWA
1234 3 ST
1234 3 FM62Q011
1234 4 BWA
1234 4 VI
1234 4 FM62Q011
Table : Sub
Std_id Grp_id Key
1234 1 BWA
1234 1 FD62E015
1234 2 BWA
1234 2 FM62Q011
期望的结果:
Std_id sub.Grp_id main.grp_id sub.Key
1234 1 1 BWA
1234 1 1 FD62E015
1234 1 2 BWA
1234 1 2 FD62E015
1234 2 3 BWA
1234 2 3 FM62Q011
1234 2 4 BWA
1234 2 4 FM62Q011
选项 1:
SELECT std_id,
grp_id,
key
FROM (
SELECT m.*,
COUNT(DISTINCT m.key) OVER (PARTITION BY m.std_id, m.grp_id) AS num_keys
FROM main m
INNER JOIN sub s
ON ( m.std_id = s.std_id
AND CEIL(m.grp_id/2) = s.grp_id -- or some other way of mapping the grp_ids
AND m.key = s.key)
)
WHERE num_keys = 2;
选项 2:
您可以创建一个 user-defined 集合类型:
CREATE TYPE string_list AS TABLE OF VARCHAR2(20);
然后使用:
SELECT m.std_id,
m.grp_id,
m.key
FROM (SELECT m.*,
CAST(
COLLECT(key) OVER(PARTITION BY std_id, grp_id)
AS string_list
) AS keys
FROM main m
) m
INNER JOIN
(SELECT s.*,
CAST(
COLLECT(key) OVER(PARTITION BY std_id, grp_id)
AS string_list
) AS keys
FROM sub s
) s
ON ( m.std_id = s.std_id
AND CEIL(m.grp_id/2) = s.grp_id -- or some other way of mapping the grp_ids
AND m.key = s.key
AND CARDINALITY(m.keys MULTISET INTERSECT DISTINCT s.keys) >= 2
)
其中,对于示例数据:
CREATE TABLE main (Std_id, Grp_id, Key) AS
SELECT 1234, 1, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 1, 'ST' FROM DUAL UNION ALL
SELECT 1234, 1, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 2, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 2, 'VI' FROM DUAL UNION ALL
SELECT 1234, 2, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 3, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 3, 'ST' FROM DUAL UNION ALL
SELECT 1234, 3, 'FM62Q011' FROM DUAL UNION ALL
SELECT 1234, 4, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 4, 'VI' FROM DUAL UNION ALL
SELECT 1234, 4, 'FM62Q011' FROM DUAL;
CREATE TABLE Sub (Std_id, Grp_id, Key) AS
SELECT 1234, 1, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 1, 'FD62E015' FROM DUAL UNION ALL
SELECT 1234, 2, 'BWA' FROM DUAL UNION ALL
SELECT 1234, 2, 'FM62Q011' FROM DUAL;
双输出:
STD_ID GRP_ID KEY 1234 1 BWA 1234 1 FD62E015 1234 2 BWA 1234 2 FD62E015 1234 3 BWA 1234 3 FM62Q011 1234 4 BWA 1234 4 FM62Q011
db<>fiddle here
发布所需结果后,看看是否有帮助。
SQL> with
2 tmain as
3 (select std_id, grp_id, listagg(key, ',') within group (order by key) keys
4 from main
5 where (std_id, key) in (select std_id, key from sub)
6 group by std_id, grp_id
7 ),
8 tsub as
9 (select std_id, grp_id, listagg(key, ',') within group (order by key) keys
10 from sub
11 group by std_id, grp_id
12 )
13 select s.std_id, s.grp_id, tm.grp_id main_grp_id, s.key
14 from sub s join tsub ts on ts.std_id = s.std_id and ts.grp_id = s.grp_id
15 join tmain tm on tm.std_id = ts.std_id and tm.keys = ts.keys
16 order by s.std_id, s.grp_id, tm.grp_id, s.key;
STD_ID GRP_ID MAIN_GRP_ID KEY
---------- ---------- ----------- --------
1234 1 1 BWA
1234 1 1 FD62E015
1234 1 2 BWA
1234 1 2 FD62E015
1234 2 3 BWA
1234 2 3 FM62Q011
1234 2 4 BWA
1234 2 4 FM62Q011
8 rows selected.
SQL>
tmain
和tsub
CTE 生成 新密钥(使用listagg
函数)- 然后在“主”
select
语句中使用这些新键来连接那些 table(连同“原始”sub
table,到获取您需要的其他值
使用 [NOT] EXISTS
select *
from main m
where EXISTS (
select 1
from (select distinct Grp_id from Sub) s
where NOT EXISTS (
select 1
from Sub s2
where s2.Grp_id = s.Grp_id and NOT EXISTS (
select 1
from main m2
where m2.Grp_id = m.Grp_id and s2.Key = m2.Key
)
)
);