前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Oracle ROLLUP和CUBE 用法

Oracle ROLLUP和CUBE 用法

作者头像
用户1148526
发布2019-05-25 19:37:35
1.1K0
发布2019-05-25 19:37:35
举报
文章被收录于专栏:Hadoop数据仓库Hadoop数据仓库

Oracle的GROUP BY语句除了最基本的语法外,还支持ROLLUP和CUBE语句。如果是ROLLUP(A, B, C)的话,首先会对(A、B、C)进行GROUP BY,然后对(A、B)进行GROUP BY,然后是(A)进行GROUP BY,最后对全表进行GROUP BY操作。如果是GROUP BY CUBE(A, B, C),则首先会对(A、B、C)进行GROUP BY,然后依次是(A、B),(A、C),(A),(B、C),(B),(C),最后对全表进行GROUP BY操作。 grouping_id()可以美化效果:

Oracle的GROUP BY语句除了最基本的语法外,还支持ROLLUP和CUBE语句。

除本文内容外,你还可参考: 分析函数参考手册: http://xsb.itpub.net/post/419/33028 分析函数使用例子介绍:http://xsb.itpub.net/post/419/44634

SQL> create table t as select * from dba_indexes;

表已创建。

SQL> select index_type, status, count(*) from t group by index_type, status;

INDEX_TYPE STATUS COUNT(*) --------------------------- -------- ---------- LOB VALID 51 NORMAL N/A 25 NORMAL VALID 479 CLUSTER VALID 11

下面来看看ROLLUP和CUBE语句的执行结果。

SQL> select index_type, status, count(*) from t group by rollup(index_type, status);

INDEX_TYPE STATUS COUNT(*) --------------------------- -------- ---------- LOB VALID 51 LOB 51 NORMAL N/A 25 NORMAL VALID 479 NORMAL 504 CLUSTER VALID 11 CLUSTER 11 566

已选择8行。

SQL> select index_type, status, count(*) from t group by cube(index_type, status);

INDEX_TYPE STATUS COUNT(*) --------------------------- -------- ---------- 566 N/A 25 VALID 541 LOB 51 LOB VALID 51 NORMAL 504 NORMAL N/A 25 NORMAL VALID 479 CLUSTER 11 CLUSTER VALID 11

已选择10行。

查询结果不是很一目了然,下面通过Oracle提供的函数GROUPING来整理一下查询结果。

SQL> select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*) 2 from t group by rollup(index_type, status) order by 1, 2;

G_IND G_ST INDEX_TYPE STATUS COUNT(*) ---------- ---------- --------------------------- -------- ---------- 0 0 LOB VALID 51 0 0 NORMAL N/A 25 0 0 NORMAL VALID 479 0 0 CLUSTER VALID 11 0 1 LOB 51 0 1 NORMAL 504 0 1 CLUSTER 11 1 1 566

已选择8行。

这个查询结果就直观多了,和不带ROLLUP语句的GROUP BY相比,ROLLUP增加了对INDEX_TYPE的GROUP BY统计和对所有记录的GROUP BY统计。

也就是说,如果是ROLLUP(A, B, C)的话,首先会对(A、B、C)进行GROUP BY,然后对(A、B)进行GROUP BY,然后是(A)进行GROUP BY,最后对全表进行GROUP BY操作。

下面看看CUBE语句。

SQL> select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*) 2 from t group by cube(index_type, status) order by 1, 2;

G_IND G_ST INDEX_TYPE STATUS COUNT(*) ---------- ---------- --------------------------- -------- ---------- 0 0 LOB VALID 51 0 0 NORMAL N/A 25 0 0 NORMAL VALID 479 0 0 CLUSTER VALID 11 0 1 LOB 51 0 1 NORMAL 504 0 1 CLUSTER 11 1 0 N/A 25 1 0 VALID 541 1 1 566

已选择10行。

和ROLLUP相比,CUBE又增加了对STATUS列的GROUP BY统计。

如果是GROUP BY CUBE(A, B, C),则首先会对(A、B、C)进行GROUP BY,然后依次是(A、B),(A、C),(A),(B、C),(B),(C),最后对全表进行GROUP BY操作。

除了使用GROUPING函数,还可以使用GROUPING_ID来标识GROUP BY结果。

SQL> select grouping_id(index_type, status) g_ind, index_type, status, count(*) 2 from t group by rollup(index_type, status) order by 1;

G_IND INDEX_TYPE STATUS COUNT(*) ---------- --------------------------- -------- ---------- 0 LOB VALID 51 0 NORMAL N/A 25 0 NORMAL VALID 479 0 CLUSTER VALID 11 1 LOB 51 1 NORMAL 504 1 CLUSTER 11 3 566

已选择8行。

SQL> select grouping_id(index_type, status) g_ind, index_type, status, count(*) 2 from t group by cube(index_type, status) order by 1;

G_IND INDEX_TYPE STATUS COUNT(*) ---------- --------------------------- -------- ---------- 0 LOB VALID 51 0 NORMAL N/A 25 0 NORMAL VALID 479 0 CLUSTER VALID 11 1 LOB 51 1 NORMAL 504 1 CLUSTER 11 2 N/A 25 2 VALID 541 3 566

已选择10行。

grouping_id()可以美化效果:

select DECODE(GROUPING_ID(C1), 1, '合计', C1) D1, DECODE(GROUPING_ID(C1, C2), 1, '小计', C2) D2, DECODE(GROUPING_ID(C1, C2, C1 + C2), 1, '小计', C1 + C2) D3, count(*), GROUPING_ID(C1, C2, C1 + C2, C1 + 1, C2 + 1), GROUPING_ID(C1) from T2 group by rollup(C1, C2, C1 + C2, C1 + 1, C2 + 1);

===========================================================

1.报表合计专用的Rollup函数

销售报表

广州 1月 2000元

广州 2月 2500元

广州 4500元

深圳 1月 1000元

深圳 2月 2000元

深圳 3000元

所有地区 7500元

以往的查询SQL:

Select area,month,sum(money) from SaleOrder group by area,month

然后广州,深圳的合计和所有地区合计都需要在程序里自行累计

1.其实可以使用如下SQL:

Select area,month,sum(total_sale) from SaleOrder group by rollup(area,month)

就能产生和报表一模一样的纪录

2.如果year不想累加,可以写成

Select year,month,area,sum(total_sale) from SaleOrder group by year, rollup(month,area)

另外Oracle 9i还支持如下语法:

Select year,month,area,sum(total_sale) from SaleOrder group by rollup((year,month),area)

3.如果使用Cube(area,month)而不是RollUp(area,month),除了获得每个地区的合计之外,还将获得每个月份的合计,在报表最后显示。

4.Grouping让合计列更好读

RollUp在显示广州合计时,月份列为NULL,但更好的做法应该是显示为"所有月份"

Grouping就是用来判断当前Column是否是一个合计列,1为yes,然后用Decode把它转为"所有月份"

Select Decode(Grouping(area),1,'所有地区',area) area, Decode(Grouping(month),1,'所有月份',month), sum(money) From SaleOrder Group by RollUp(area,month);

2.对多级层次查询的start with.....connect by

比如人员组织,产品类别,Oracle提供了很经典的方法

SELECT LEVEL, name, emp_id,manager_emp_id FROM employee START WITH manager_emp_id is null CONNECT BY PRIOR emp_id = manager_emp_id;

上面的语句demo了全部的应用,start with指明从哪里开始遍历树,如果从根开始,那么它的manager应该是Null,如果从某个职员开始,可以写成emp_id='11'

CONNECT BY 就是指明父子关系,注意PRIOR位置

另外还有一个LEVEL列,显示节点的层次

3.更多报表/分析决策功能

3.1 分析功能的基本结构

分析功能() over( partion子句,order by子句,窗口子句)

概念上很难讲清楚,还是用例子说话比较好.

3.2 Row_Number 和 Rank, DENSE_Rank

用于选出Top 3 sales这样的报表

当两个业务员可能有相同业绩时,就要使用Rank和Dense_Rank

比如

金额 RowNum Rank Dense_Rank

张三 4000元 1 1 1

李四 3000元 2 2 2

钱五 2000元 3 3 3

孙六 2000元 4 3 3

丁七 1000元 5 5 4

这时,应该把并列第三的钱五和孙六都选进去,所以用Ranking功能比RowNumber保险.至于Desnse还是Ranking就看具体情况了。

SELECT salesperson_id, SUM(tot_sales) sp_sales, RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rankFROM orders GROUP BY salesperson_id

3.3 NTILE 把纪录平分成甲乙丙丁四等

比如我想取得前25%的纪录,或者把25%的纪录当作同一个level平等对待,把另25%当作另一个Level平等对待

SELECT cust_nbr, SUM(tot_sales) cust_sales, NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartileFROM orders GROUP BY cust_nbr ORDER BY 3,2 DESC;

NTITLE(4)把纪录以 SUM(tot_sales)排序分成4份.

3.4 辅助分析列和Windows Function

报表除了基本事实数据外,总希望旁边多些全年总销量,到目前为止的累计销量,前后三个月的平均销量这样的列来参考.

这种前后三个月的平均和到目前为止的累计销量就叫windows function, 见下例

SELECT month, SUM(tot_sales) monthly_sales, SUM(SUM(tot_sales)) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding FROM orders GROUP BY month ORDER BY month;

SELECT month, SUM(tot_sales) monthly_sales, AVG(SUM(tot_sales)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg FROM orders GROUP BY month ORDER BY month;

Windows Function的关键就是Windows子句的几个取值

1 PRECEDING 之前的一条记录

1 FOLLOWING 之后的一条记录

UNBOUNDED PRECEDING 之前的所有记录

CURRENT ROW 当前纪录

4.SubQuery总结

SubQuery天天用了,理论上总结一下.SubQuery 分三种

1.Noncorrelated 子查询 最普通的样式.

2.Correlated Subqueries 把父查询的列拉到子查询里面去,头一回cyt教我的时候理解了半天.

3.Inline View 也被当成最普通的样式用了.

然后Noncorrelated 子查询又有三种情况

1.返回一行一列 where price < (select max(price) from goods )

2.返回多行一列 where price>= ALL (select price from goods where type=2)

or where NOT price< ANY(select price from goods where type=2)

最常用的IN其实就是=ANY()

3.返回多行多列 一次返回多列当然就节省了查询时间

UPDATE monthly_orders SET (tot_orders, max_order_amt) = (SELECT COUNT(*), MAX(sale_price) FROM cust_order)DELETE FROM line_item WHERE (order_nbr, part_nbr) IN (SELECT order_nbr, part_nbr FROM cust_order c)

======================================== /*--------理解grouping sets select a, b, c, sum( d ) from t group by grouping sets ( a, b, c )

等效于

select * from ( select a, null, null, sum( d ) from t group by a union all select null, b, null, sum( d ) from t group by b union all select null, null, c, sum( d ) from t group by c ) */

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年12月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档