Oracle:通过 union 左右组合两个 group by 查询(使用聚合函数 count())以获得合并结果

Oracle: Combine two group by queries (which use aggregate function count()) by union or so to get a consolidated result

我有两张桌子。 TABLE_ATABLE_B.

两个表都保留要保存的列CREATION_USER。但是这个列在各个表中有不同的名称。

我的动机是计算每个用户在两个表中创建的记录数。 也就是说,将这两个查询的结果与很少的条件结合起来。用户名不能重复,并且在两个表中都有记录的用户名,计数应该是他们的总和。

SELECT A.CREATION_USER_A AS "USER",
COUNT(*)
FROM TABLE_A A
GROUP BY A.CREATION_USER_A;

SELECT B.CREATION_USER_B AS "USER",
COUNT(*)
FROM TABLE_B B
GROUP BY B.CREATION_USER_B;

例如,

USER_A 在 TABLE_A、

中创建了 2 条记录

USER_B 在 TABLE_B 和

中创建了 3 条记录

USER_C 在 TABLE_A 中创建了 4 条记录,在 TABLE_B 中创建了 3 条记录。

所以输出应该是这样的:

|  USER  | COUNT |
| USER_A | 2     |
| USER_B | 3     |
| USER_C | 7     |

我已经编写了一个执行此操作的查询,但它的性能非常糟糕。

SELECT A.CREATION_USER_A AS "USER",
(COUNT(A.CREATION_USER_A)+(SELECT COUNT(CREATION_USER_B) FROM TABLE_B WHERE CREATION_USER_B = A.CREATION_USER_A)) AS "COUNT"
FROM TABLE_A A
GROUP BY A.CREATION_USER_A
UNION
SELECT B.CREATION_USER_B,
COUNT(B.CREATION_USER_B)
FROM TABLE_B B
WHERE B.CREATION_USER_B NOT IN (SELECT CREATION_USER_A FROM TABLE_A)
GROUP BY B.CREATION_USER_B;

请提出完成此任务的方法。

您可以简单地构建一个由表中所有记录的并集(保留重复项)给出的集合,然后按创建用户对记录分组进行计数:

生成一些示例数据:

create table table_a(id, creation_user_a) as ( 
    select 1, 'USER_A' from dual union all
    select 1, 'USER_A' from dual union all
    select 1, 'USER_C' from dual union all
    select 1, 'USER_C' from dual union all
    select 1, 'USER_C' from dual union all
    select 1, 'USER_C' from dual
);

create table table_b(id, creation_user_b) as ( 
    select 1, 'USER_B' from dual union all
    select 1, 'USER_B' from dual union all
    select 1, 'USER_B' from dual union all
    select 1, 'USER_C' from dual union all
    select 1, 'USER_C' from dual union all
    select 1, 'USER_C' from dual
)

查询:

select count(1), creation_user
from ( /* the union of all the records from table_a and table_b */
       select creation_user_a as creation_user from table_a
       union all /* UNION ALL keeps duplicates */
       select creation_user_B from table_b
     )
group by creation_user 
order by creation_user 

结果:

2   USER_A
3   USER_B
7   USER_C

解释计划:

---------------------------------------------------------------------------------
| Id  | Operation             | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |    12 |    96 |     8  (25)| 00:00:01 |
|   1 |  SORT ORDER BY        |         |    12 |    96 |     8  (25)| 00:00:01 |
|   2 |   HASH GROUP BY       |         |    12 |    96 |     8  (25)| 00:00:01 |
|   3 |    VIEW               |         |    12 |    96 |     6   (0)| 00:00:01 |
|   4 |     UNION-ALL         |         |       |       |            |          |
|   5 |      TABLE ACCESS FULL| TABLE_A |     6 |    48 |     3   (0)| 00:00:01 |
|   6 |      TABLE ACCESS FULL| TABLE_B |     6 |    48 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Aleksej 的答案的另一种解决方案(但更复杂,而且可能更慢 - 您需要测试两者以进行检查)解决方案是使用完整的外部联接来联接按查询分组的两者,如下所示:

WITH table_a AS (SELECT 'USER_A' creation_user_a, 10 val FROM dual UNION ALL
                 SELECT 'USER_A' creation_user_a, 20 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_a, 30 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_a, 40 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_a, 50 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_a, 60 val FROM dual),
     table_b AS (SELECT 'USER_B' creation_user_b, 10 val FROM dual UNION ALL
                 SELECT 'USER_B' creation_user_b, 20 val FROM dual UNION ALL
                 SELECT 'USER_B' creation_user_b, 30 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_b, 40 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_b, 50 val FROM dual UNION ALL
                 SELECT 'USER_C' creation_user_b, 60 val FROM dual)
-- end of mimicking your tables with data in them. See the SQL below:
SELECT COALESCE(a.creation_user_a, b.creation_user_b) "USER",
       nvl(a.cnt_a, 0) + nvl(b.cnt_b, 0) total_records
FROM   (SELECT   creation_user_a,
                 COUNT(*) cnt_a
        FROM     table_a
        GROUP BY creation_user_a) a
       FULL OUTER JOIN (SELECT   creation_user_b,
                                 COUNT(*) cnt_b
                        FROM     table_b
                        GROUP BY creation_user_b) b ON a.creation_user_a = b.creation_user_b
ORDER BY "USER";

USER   TOTAL_RECORDS
------ -------------
USER_A             2
USER_B             3
USER_C             7

谢谢大家帮助我。我找到了一个更简单、更有效的解决方案。有效。

SELECT CREATION_USER, SUM(TOTAL_COUNT) TOTAL_COUNT FROM
(SELECT /*+ PARALLEL */ A.CREATION_USER_A CREATION_USER,
COUNT(A.CREATION_USER_A) TOTAL_COUNT
FROM TABLE_A A
GROUP BY A.CREATION_USER_A
UNION
SELECT /*+ PARALLEL */ B.CREATION_USER_B CREATION_USER,
COUNT(B.CREATION_USER_B) TOTAL_COUNT
FROM TABLE_B B
GROUP BY B.CREATION_USER_B)
GROUP BY CREATION_USER;