SQL ROLLUP还是Union?

时间:2017-02-21 11:47:34

标签: sql oracle rollup

我想获得总条目数,但不幸的是我不相信汇总将是最好的选择:

SELECT BUSINESS_STATUS_NAME,
  PENDING_ITEMS,
  DATAGROUP
FROM PAYMENTS
WHERE STATUS LIKE '%PROCESS%';

This Produces:

BUSINESS_STATUS_NAME     PENDING_ITEMS     DATAGROUP
PROCESSING DATA          34                PRODUCT
PROCESSING INS           40                SERVICE

我想在下面获得一个总计,但是ROLLUP给了我小计,因为它包含数据组列。我只需要待处理项目的总计,但我需要显示数据组。使用sum(pending_items)选择查询会对UNION更好吗?

BUSINESS_STATUS_NAME     PENDING_ITEMS     DATAGROUP
PROCESSING DATA          34                PRODUCT
PROCESSING INS           40                SERVICE
GRAND TOTAL **           74

谢谢!

2 个答案:

答案 0 :(得分:4)

为了清晰度和性能,我会使用ROLLUP

假设你有一个这样的样本表:

create table payments (business_status_name, pending_items, datagroup) as (
    select 'PROCESSING DATA', 10, 'PRODUCT' from dual union all
    select 'PROCESSING DATA',  5, 'PRODUCT' from dual union all
    select 'PROCESSING DATA',  2, 'SERVICE' from dual union all
    select 'PROCESSING INS',  10, 'SERVICE' from dual union all
    select 'PROCESSING INS',  10, 'SERVICE' from dual union all
    select 'PROCESSING INS',  10, 'PRODUCT' from dual
)

这是ROLLUP的一种方式(注意括号改变分组逻辑):

SELECT BUSINESS_STATUS_NAME,
       SUM(PENDING_ITEMS) as PENDING_ITEMS,
       DATAGROUP
FROM PAYMENTS
GROUP BY ROLLUP ((BUSINESS_STATUS_NAME, DATAGROUP))

结果:

BUSINESS_STATUS PENDING_ITEMS DATAGRO
--------------- ------------- -------
PROCESSING INS             10 PRODUCT
PROCESSING INS             20 SERVICE
PROCESSING DATA            15 PRODUCT
PROCESSING DATA             2 SERVICE
                           47

计划:

---------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |          |     6 |   186 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY ROLLUP|          |     6 |   186 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | PAYMENTS |     6 |   186 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

这是UNION ALL

SELECT BUSINESS_STATUS_NAME,
       SUM(PENDING_ITEMS) as PENDING_ITEMS,
       DATAGROUP
FROM PAYMENTS
GROUP BY BUSINESS_STATUS_NAME, DATAGROUP
UNION ALL
SELECT NULL, SUM(PENDING_ITEMS), NULL
FROM PAYMENTS;

结果与ROLLUP相同:

BUSINESS_STATUS PENDING_ITEMS DATAGRO
--------------- ------------- -------
PROCESSING INS             20 SERVICE
PROCESSING INS             10 PRODUCT
PROCESSING DATA            15 PRODUCT
PROCESSING DATA             2 SERVICE
                           47

计划不太好,TWO FULL SCANS

--------------------------------------------------------------------------------
| Id  | Operation           | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |          |     7 |   199 |     7  (58)| 00:00:01 |
|   1 |  UNION-ALL          |          |       |       |            |          |
|   2 |   HASH GROUP BY     |          |     6 |   186 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| PAYMENTS |     6 |   186 |     3   (0)| 00:00:01 |
|   4 |   SORT AGGREGATE    |          |     1 |    13 |            |          |
|   5 |    TABLE ACCESS FULL| PAYMENTS |     6 |    78 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

这当然只是一个带有少量记录,没有索引的小例子......所以实际表格上的内容可能会有所不同,但我仍然认为ROLLUP应该比UNION ALL表现得更好。

在一个更简单的情况下,与你的完全相同,这将是两种方法的计划:

SELECT BUSINESS_STATUS_NAME,
       SUM(PENDING_ITEMS) as PENDING_ITEMS,
       DATAGROUP
FROM PAYMENTS
GROUP BY ROLLUP ((BUSINESS_STATUS_NAME, DATAGROUP))

---------------------------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |          |     2 |    62 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY ROLLUP|          |     2 |    62 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | PAYMENTS |     2 |    62 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

SELECT BUSINESS_STATUS_NAME,
       PENDING_ITEMS,
       DATAGROUP
FROM PAYMENTS
UNION ALL 
SELECT NULL, 
       SUM(PENDING_ITEMS),
       NULL
FROM PAYMENTS    

--------------------------------------------------------------------------------
| Id  | Operation           | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |          |     3 |    75 |     6  (50)| 00:00:01 |
|   1 |  UNION-ALL          |          |       |       |            |          |
|   2 |   TABLE ACCESS FULL | PAYMENTS |     2 |    62 |     3   (0)| 00:00:01 |
|   3 |   SORT AGGREGATE    |          |     1 |    13 |            |          |
|   4 |    TABLE ACCESS FULL| PAYMENTS |     2 |    26 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

ROLLUP仍然有一个更好的计划,只有一次表扫描。

答案 1 :(得分:0)

您可以使用rollup,但需要汇总查询:

SELECT BUSINESS_STATUS_NAME,
       SUM(PENDING_ITEMS) as PENDING_ITEMS,
       DATAGROUP
FROM PAYMENTS
WHERE STATUS LIKE '%PROCESS%'
GROUP BY ROLLUP (BUSINESS_STATUS_NAME, DATAGROUP);

我怀疑这个union all之间存在性能差异。但请注意,这可以保证将摘要行作为结果集中的最后一行。