SQL 그룹화는 OLAP 시나리오에서 합계 및 부분합 문제를 해결합니다. 해당 구문은 여러 범주로 구분되지만 동일한 문제를 해결해야 합니다.
ROLLUP과 CUBE는 규칙을 캡슐화하는 GROUPING SETS이며 GROUPING SETS는 가장 원시적인 규칙입니다.
이해의 편의를 위해 문제부터 시작하여 문제를 해결해 보겠습니다.
바닥 테이블
위의 샘플 하단 테이블에는 8 개의 데이터가 있으며 도시 1, 도시 2 2 개의 도시가 있으며 아래에는 각각 영역 1 ~ 4가 있으며 각 데이터에는 데이터의 인구 수가 있습니다.
이제 총 인구와 각 도시의 소계를 계산하고 싶습니다. 그룹화 구문을 마스터하기 전에 두 개의 select 문을 결합한 후에만 그룹화 구문을 얻을 수 있습니다.
SELECT city, sum(people) FROM test GROUP BY city
union
SELECT '合计' as city, sum(people) FROM test
复制代码
그러나 두 개의 select 문은 두 번 집계되며 성능은 작은 오버헤드가 아니므로 SQL은 이 문제를 해결하기 위해 GROUPING SETS 구문을 제공합니다.
그룹화 세트
GROUP BY GROUPING SETS는 모든 집계 항목을 지정할 수 있습니다.예를 들어 합계와 그룹 합계를 동시에 계산하려면 빈 내용에 따라 GROUP BY를 수행하고 합계를 수행한 다음 a를 수행해야 합니다. 도시에 따라 GROUP BY를 수행하고 합계를 수행하고 GROUPING SETS로 대체합니다. 설명은 다음과 같습니다.
SELECT
city, area,
sum(people)
FROM test
GROUP BY GROUPING SETS((), (city, area))
复制代码
GROUPING SETS((), (city, area))
여기서 합계는 각각 ()
에 의해 계산되고 (city, area)
집계됨을 나타냅니다. 반환된 결과는 다음과 같습니다.
보시다시피 NULL 값이 있는 행은 우리가 원하는 합계이며 해당 값은 GROUP BY 제한 없이 계산됩니다.
마찬가지로 GROUP BY 조건의 수와 조합을 GROUPING SETS((), (city), (city, area), (area))
작성할 .
이 규칙에 의해 계산된 데이터를 "수퍼 그룹 레코드"라고 합니다. "슈퍼 그룹화 레코드"에 의해 생성된 NULL 값은 실제 NULL 값과 혼동되기 쉽기 때문에 SQL은 이 문제를 해결하기 위해 GROUPING 함수를 제공합니다.
기능 그룹화
수퍼 그룹 레코드에 의해 생성된 NULL은 다음 GROUPING()
함수 .
SELECT
GROUPING(city),
GROUPING(area),
sum(people)
FROM test
GROUP BY GROUPING SETS((), (city, area))
复制代码
구체적인 효과는 다음 그림에 나와 있습니다.
可以看到,但凡是超级分组计算出来的字段都会识别为 1,我们利用之前学习的 SQL CASE 表达式 将其转换为总计、小计字样,就可以得出一张数据分析表了:
SELECT
CASE WHEN GROUPING(city) = 1 THEN '总计' ELSE city END,
CASE WHEN GROUPING(area) = 1 THEN '小计' ELSE area END,
sum(people)
FROM test
GROUP BY GROUPING SETS((), (city, area))
复制代码
然后前端表格展示时,将第一行 “总计”、“小计” 单元格合并为 “总计”,就完成了总计这个 BI 可视化分析功能。
ROLLUP
ROLLUP 是卷起的意思,是一种特定规则的 GROUPING SETS,以下两种写法是等价的:
SELECT sum(people) FROM test
GROUP BY ROLLUP(city)
-- 等价于
SELECT sum(people) FROM test
GROUP BY GROUPING SETS((), (city))
复制代码
再看一组等价描述:
SELECT sum(people) FROM test
GROUP BY ROLLUP(city, area)
-- 等价于
SELECT sum(people) FROM test
GROUP BY GROUPING SETS((), (city), (city, area))
复制代码
发现规律了吗?ROLLUP 会按顺序把 GROUP BY 内容 “一个个卷起来”。用 GROUPING 函数判断超级分组记录对 ROLLUP 同样适用。
CUBE
CUBE 又有所不同,它对内容进行了所有可能性展开(所以叫 CUBE)。
类比上面的例子,我们再写两组等价的展开:
SELECT sum(people) FROM test
GROUP BY CUBE(city)
-- 等价于
SELECT sum(people) FROM test
GROUP BY GROUPING SETS((), (city))
复制代码
上面的例子因为只有一项还看不出来,下面两项分组就能看出来了:
SELECT sum(people) FROM test
GROUP BY CUBE(city, area)
-- 等价于
SELECT sum(people) FROM test
GROUP BY GROUPING SETS((), (city), (area), (city, area))
复制代码
所谓 CUBE,是一种多维形状的描述,二维时有 2^1 种展开,三维时有 2^2 种展开,四维、五维依此类推。可以想象,如果用 CUBE 描述了很多组合,复杂度会爆炸。
总结
学习了 GROUPING 语法,以后前端同学的你不会再纠结这个问题了吧:
产品开启了总计、小计,我们是额外取一次数还是放到一起获取啊?
这个问题的标准答案和原理都在这篇文章里了。PS:对于不支持 GROUPING 语法数据库,要想办法屏蔽,就像前端 polyfill 一样,是一种降级方案。至于如何屏蔽,参考文章开头提到的两个 SELECT + UNION。
如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)