经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MS SQL Server » 查看文章
GROUP BY中的WITH CUBE、WITH ROLLUP原理测试及GROUPING应用
来源:cnblogs  作者:缥缈的尘埃  时间:2019/11/5 10:24:02  对本文有异议

    前几天,看到一个群友用WITH ROLLUP运算符。由于自个儿没用过,看到概念及结果都云里雾里的,所以突然来了兴趣对生成结果测了一番。

    一、概念:

    WITH CUBE:生成的结果集显示了所选列中值的所有组合的聚合。

    WITH ROLLUP:生成的结果集显示了所选列中值的某一层次结构的聚合。

    GROUPING:当行由 WITH CUBE或WITH ROLLUP运算符添加时,该函数将导致附加列的输出值为 1;当行不由 CUBE 或 ROLLUP 运算符添加时,该函数将导致附加列的输出值为 0。仅在与包含 CUBE 或 ROLLUP 运算符的 GROUP BY 子句相关联的选择列表中才允许分组。

    二、测试:

    1、建立临时表

  1. CREATE TABLE #T0
  2. (
  3. [GRADE] [VARCHAR](50) NULL, --年级
  4. [CLASS] [VARCHAR](50) NULL, --班级
  5. [NAME] [VARCHAR](50) NULL, --姓名
  6. [COURSE] [VARCHAR](50) NULL, --学科
  7. [RESULT] [NUMERIC](8,2) NULL --成绩
  8. )
  9. CREATE TABLE #T1
  10. (
  11. [ID] [INT] IDENTITY(1,1) NOT NULL, --序号
  12. [GRADE] [VARCHAR](50) NULL, --年级
  13. [CLASS] [VARCHAR](50) NULL, --班级
  14. [NAME] [VARCHAR](50) NULL, --姓名
  15. [COURSE] [VARCHAR](50) NULL, --学科
  16. [RESULT] [NUMERIC](8,2) NULL --成绩
  17. )
  18. CREATE TABLE #T2
  19. (
  20. [ID] [INT] IDENTITY(1,1) NOT NULL, --序号
  21. [GRADE] [VARCHAR](50) NULL, --年级
  22. [CLASS] [VARCHAR](50) NULL, --班级
  23. [NAME] [VARCHAR](50) NULL, --姓名
  24. [COURSE] [VARCHAR](50) NULL, --学科
  25. [RESULT] [NUMERIC](8,2) NULL --成绩
  26. )

     2、插入测试数据

  1. INSERT INTO #T0 (GRADE,CLASS,NAME,COURSE,RESULT)
  2. SELECT '2019','CLASS1','9A01','C#',100
  3. UNION
  4. SELECT '2019','CLASS1','9A02','C#',100
  5. UNION
  6. SELECT '2019','CLASS2','9B01','C#',100
  7. UNION
  8. SELECT '2019','CLASS2','9B02','C#',100
  9. UNION
  10. SELECT '2018','CLASS1','8A01','JAVA',100
  11. UNION
  12. SELECT '2018','CLASS1','8A02','JAVA',100
  13. UNION
  14. SELECT '2018','CLASS2','8B01','JAVA',100
  15. UNION
  16. SELECT '2018','CLASS2','8B02','JAVA',100

    查询T0表结果:

    3、GROUP BY

    抛砖引玉,看看常用的GROUP BY排序:默认以SELECT字段顺序(GRADE->CLASS->NAME->COURSE)进行排序,以下两种查询结果是一样的。

  1. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  2. FROM #T0
  3. GROUP BY GRADE,CLASS,NAME,COURSE
  4. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  5. FROM #T0
  6. GROUP BY GRADE,CLASS,NAME,COURSE
  7. ORDER BY GRADE,CLASS,NAME,COURSE

    4、WITH CUBE

    原理1:以GROUP BY字段依次赋以NULL值进行分组聚合。

    原理2:第1个字段(即GRADE字段)生成结果:除原始数据外,以第1个字段固定赋以NULL值,然后其它字段依次赋以NULL值进行分组聚合,结果由右往左进行排序

    下面开始测第1个字段的结果是怎么来的:

  1. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  2. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  3. FROM #T0
  4. GROUP BY GRADE,CLASS,NAME,COURSE
  5. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  6. SELECT 'ZZ' GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  7. FROM #T0
  8. GROUP BY CLASS,NAME,COURSE
  9. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  10. SELECT 'ZZ' GRADE,'ZZ' CLASS,NAME,COURSE,SUM(RESULT) RESULT
  11. FROM #T0
  12. GROUP BY NAME,COURSE
  13. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  14. SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,COURSE,SUM(RESULT) RESULT
  15. FROM #T0
  16. GROUP BY COURSE
  17. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  18. SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT
  19. FROM #T0
  20. --1个字段结果排序由右往左
  21. INSERT INTO #T2 (GRADE,CLASS,NAME,COURSE,RESULT)
  22. SELECT GRADE,CLASS,NAME,COURSE,RESULT FROM #T1 WHERE ID BETWEEN 1 AND 27 ORDER BY COURSE,NAME,CLASS,GRADE
  23. UPDATE #T2 SET GRADE=NULL WHERE GRADE='ZZ'
  24. UPDATE #T2 SET CLASS=NULL WHERE CLASS='ZZ'
  25. UPDATE #T2 SET NAME=NULL WHERE NAME='ZZ'
  26. UPDATE #T2 SET COURSE=NULL WHERE COURSE='ZZ'

    WITH CUBE的结果:

  1. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  2. FROM #T0
  3. GROUP BY GRADE,CLASS,NAME,COURSE
  4. WITH CUBE

    自已测试的结果:

  1. SELECT * FROM #T2

    结果与上面一致。

    其它字段优先跟哪个字段组合、最终怎样排序?呃,测过,没搞清楚……

    5、WITH ROLLUP

    原理1:除原始数据外,以GROUP BY最后1个字段(即COURSE字段)固定赋以NULL值,然后其它字段依次赋以NULL值进行分组聚合,结果由左往右进行排序

    这个跟WITH CUBE的第1个字段非常相象:一个是第1个字段,一个是最后1个字段;一个结果是由右往左排序,一个结果是由左往右排序。

    下面开始测结果是怎么来的:

  1. TRUNCATE TABLE #T1
  2. TRUNCATE TABLE #T2
  3. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  4. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  5. FROM #T0
  6. GROUP BY GRADE,CLASS,NAME,COURSE
  7. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  8. SELECT GRADE,CLASS,NAME,'ZZ' COURSE,SUM(RESULT) RESULT
  9. FROM #T0
  10. WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS=#T0.GRADE AND NAME=#T0.NAME AND COURSE='ZZ')
  11. GROUP BY GRADE,CLASS,NAME
  12. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  13. SELECT GRADE,CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT
  14. FROM #T0
  15. WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS=#T0.CLASS AND NAME='ZZ' AND COURSE='ZZ')
  16. GROUP BY GRADE,CLASS
  17. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  18. SELECT GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT
  19. FROM #T0
  20. WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS='ZZ' AND NAME='ZZ' AND COURSE='ZZ')
  21. GROUP BY GRADE
  22. INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT)
  23. SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT
  24. FROM #T0
  25. --结果排序由左往右
  26. INSERT INTO #T2 (GRADE,CLASS,NAME,COURSE,RESULT)
  27. SELECT GRADE,CLASS,NAME,COURSE,RESULT FROM #T1 ORDER BY GRADE,CLASS,NAME,COURSE
  28. UPDATE #T2 SET GRADE=NULL WHERE GRADE='ZZ'
  29. UPDATE #T2 SET CLASS=NULL WHERE CLASS='ZZ'
  30. UPDATE #T2 SET NAME=NULL WHERE NAME='ZZ'
  31. UPDATE #T2 SET COURSE=NULL WHERE COURSE='ZZ'

    WITH ROLLUP的结果:

  1. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT
  2. FROM #T0
  3. GROUP BY GRADE,CLASS,NAME,COURSE
  4. WITH ROLLUP

    自己测试的结果:

  1. SELECT * FROM #T2

    结果与上面一致。

    6、GROUPING

    这个就比较容易理解了,WITH CUBE与WITH ROLLUP用法一样,先看结果:

  1. SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT,GROUPING(COURSE) [GROUPING]
  2. FROM #T0
  3. GROUP BY GRADE,CLASS,NAME,COURSE
  4. WITH ROLLUP

    上面GROUPING的是COURSE字段,有NULL值就是WITH ROLLUP额外添加的,GROUPING结果值为1。

    有了GROUPING,那做小计、总计就方便了。

  1. SELECT
  2. GRADE,
  3. CASE WHEN GROUPING(GRADE)=1 AND GROUPING(CLASS)=1 THEN '总计' WHEN GROUPING(GRADE)=0 AND GROUPING(CLASS)=1 THEN '小计' ELSE CLASS END CLASS,
  4. NAME,COURSE,SUM(RESULT) RESULT
  5. FROM #T0
  6. GROUP BY GRADE,CLASS,NAME,COURSE
  7. WITH ROLLUP

     好了,原理测试及应用就到这里结束了。

原文链接:http://www.cnblogs.com/atomy/p/11795921.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号