在 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>
  • tmaintsub 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
             )
         )
    );

db<>fiddle