【问题标题】:Oracle: Combine two group by queries (which use aggregate function count()) by union or so to get a consolidated resultOracle:通过联合左右组合两个分组查询(使用聚合函数count())以获得合并结果
【发布时间】:2017-01-11 09:47:43
【问题描述】:

我有两张桌子。 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;

请建议一种方法来完成这项工作。

【问题讨论】:

    标签: oracle join group-by oracle10g union


    【解决方案1】:

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

    构建一些示例数据:

    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 |
    ---------------------------------------------------------------------------------
    

    【讨论】:

    • 感谢您的帮助。
    【解决方案2】:

    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
    

    【讨论】:

    • 感谢您的帮助。
    【解决方案3】:

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

    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;
    

    【讨论】:

    • 您需要UNION ALL。如果您有 UNION 将不会给出正确的结果,例如 USER_D 在 table_A 中创建了 1 条记录,在 table_B 中创建了 1 条记录。我怀疑这会比我们给你的解决方案更有效
    • 是的,我同意 UNION ALL 部分。但是我明白了,您在查询中对用户名进行了硬编码——这就是我所理解的。如我错了请纠正我。我为什么要那么做?我有 > 20M 条记录。
    • 我在哪里硬编码了用户名?我的代码的第一部分仅用于构建测试用例;在查询部分,我只使用列名
    • 抱歉,我误读了您的回答。我试过了,效果很好!非常感谢!
    • 好的,刚刚编辑以使其更清晰。如果您认为这是对您的正确答案,请接受。
    猜你喜欢
    • 2023-04-09
    • 1970-01-01
    • 2019-05-06
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2018-03-17
    相关资源
    最近更新 更多