关于javascript:SQL-聚合查询

6次阅读

共计 3170 个字符,预计需要花费 8 分钟才能阅读完成。

SQL 为什么要反对聚合查问呢?

这看上去是个童稚的问题,但咱们还是一步步思考一下。数据以行为粒度存储,最简略的 SQL 语句是 select * from test,拿到的是整个二维表明细,但仅做到这一点远远不够,出于以下两个目标,须要 SQL 提供聚合函数:

  1. 明细数据没有统计意义,比方我想晓得明天的营业额一共有多少,而不太关怀某桌客人生产了多少。
  2. 尽管能够先把数据查到内存中再聚合,但在数据量十分大的状况下很容易把内存撑爆,可能一张表一天的数据量就有 10TB,而 10TB 数据就算能读到内存里,聚合计算可能也会慢到难以承受。

另外聚合自身也有肯定逻辑复杂度,而 SQL 提供了聚合函数与分组聚合能力,能够不便疾速的统计出有业务价值的聚合数据,这奠定了 SQL 语言的剖析价值,因而大部分剖析软件间接采纳 SQL 作为间接面向用户的表达式。

聚合函数

常见的聚合函数有:

  • COUNT:计数。
  • SUM:求和。
  • AVG:求平均值。
  • MAX:求最大值。
  • MIN:求最小值。

COUNT

COUNT 用来计算有多少条数据,比方咱们看 id 这一列有多少条:

SELECT COUNT(id) FROM test

但咱们发现其实查任何一列的 COUNT 都是一样的,那传入 id 有什么意义呢?没必要非凡找一个具体列指代呀,所以也能够写成:

SELECT COUNT(*) FROM test

但这两者存在奥妙差别。SQL 存在一种很非凡的值类型 NULL,如果 COUNT 指定了具体列,则统计时会跳过此列值为 NULL 的行,而 COUNT(*) 因为未指定具体列,所以就算蕴含了 NULL,甚至某一行所有列都为 NULL,也都会蕴含进来。所以 COUNT(*) 查出的后果肯定大于等于 COUNT(c1)

当然任何聚合函数都能够追随查问条件 WHERE,比方:

SELECT COUNT(*) FROM test
WHERE is_gray = 1

SUM

SUM 求和所有项,因而必须作用于数值字段,而不能用于字符串。

SELECT SUM(cost) FROM test

SUM 遇到 NULL 值时当 0 解决,因为这等价于疏忽。

AVG

AVG 求所有项均值,因而必须作用于数值字段,而不能用于字符串。

SELECT AVG(cost) FROM test

AVG 遇到 NULL 值时采纳了最彻底的疏忽形式,即 NULL 齐全不参加分子与分母的计算,就像这一行数据不存在一样。

MAX、MIN

MAX、MIN 别离求最大与最小值,下面不同的时,也能够作用于字符串上,因而能够依据字母判断大小,从大到小顺次对应 a-z,但即使能算,也没有实际意义且不好了解,因而不倡议对字符串求极值。

SELECT MAX(cost) FROM test

多个聚合字段

尽管都是聚合函数,但 MAX、MIN 严格意义上不算是聚合函数,因为它们只是寻找了满足条件的行。能够看看上面两段查问后果的比照:

SELECT MAX(cost), id FROM test -- id: 100
SELECT SUM(cost), id FROM test -- id: 1

第一条查问能够找到最大值那一行的 id,而第二条查问的 id 是无意义的,因为不晓得归属在哪一行,所以只返回了第一条数据的 id。

当然,如果同时计算 MAX、MIN,那么此时 id 也只返回第一条数据的值,因为这个查问后果对应了复数行:

SELECT MAX(cost), MIN(cost), id FROM test -- id: 1

基于这些个性,最好不要混用聚合与非聚合,也就是一条查问一旦有一个字段是聚合的,那么所有字段都要聚合。

当初很多 BI 引擎的自定义字段都有这条限度,因为混用聚合与非聚合在自定义内存计算时解决起来边界状况很多,尽管 SQL 能反对,但业务自定义的函数可能不反对。

分组聚合

分组聚合就是 GROUP BY,其实能够把它当作一种高级的条件语句。

举个例子,查问每个国家的 GDP 总量:

SELECT COUNT(GDP) FROM amazing_table
GROUP BY country

返回的后果就会依照国家进行分组,这时,聚合函数就变成了在组内聚合。

其实如果咱们只想看中、美的 GDP,用非分组也能够查,只是要分成两条 SQL:

SELECT COUNT(GDP) FROM amazing_table
WHERE country = '中国'

SELECT COUNT(GDP) FROM amazing_table
WHERE country = '美国'

所以 GROUP BY 也可了解为,将某个字段的所有可枚举的状况都查了进去,并整合成一张表,每一行代表了一种枚举状况,不须要合成为一个个 WHERE 查问了。

多字段分组聚合

GROUP BY 能够对多个维度应用,含意等价于表格查问时行 / 列拖入多个维度。

下面是 BI 查问工具视角,如果没有上下文,能够看上面这个递进形容:

  • 依照多个字段进行分组聚合。
  • 多字段组合起来成为惟一 Key,即 GROUP BY a,b 示意 a,b 合在一起形容一个组。
  • GROUP BY a,b,c 查问后果第一列可能看到许多反复的 a 行,第二列看到反复 b 行,但在同一个 a 值内不会反复,c 在 b 行中同理。

上面是一个例子:

SELECT SUM(GDP) FROM amazing_table
GROUP BY province, city, area

查问后果为:

 浙江 杭州 余杭区
浙江 杭州 西湖区
浙江 宁波 海曙区
浙江 宁波 江北区
北京 .........

GROUP BY + WHERE

WHERE 是依据行进行条件筛选的。因而 GROUP BY + WHERE 并不是在组内做筛选,而是对整体做筛选。

但因为按行筛选,其实组内或非组内后果都齐全一样,所以咱们简直无奈感知这种差别:

SELECT SUM(GDP) FROM amazing_table
GROUP BY province, city, area
WHERE industry = 'internet'

然而,疏忽这个差别会导致咱们在聚合筛选时碰壁。

比方要筛选出平均分大于 60 学生的问题总和,如果不应用子查问,是无奈在一般查问中在 WHERE 加聚合函数实现的,比方上面就是一个语法错误的例子:

SELECT SUM(score) FROM amazing_table
WHERE AVG(score) > 60

不要空想下面的 SQL 能够执行胜利,不要在 WHERE 里应用聚合函数。

GROUP BY + HAVING

HAVING 是依据组进行条件筛选的。因而能够在 HAVING 应用聚合函数:

SELECT SUM(score) FROM amazing_table
GROUP BY class_name
HAVING AVG(score) > 60

下面的例子中能够失常查问,示意依照班级分组看总分,且仅筛选出平均分大于 60 的班级。

所以为什么 HAVING 能够应用聚合条件呢?因为 HAVING 筛选的是组,所以能够对组聚合后过滤掉不满足条件的组,这样是有意义的。而 WHERE 是针对行粒度的,聚合后全表就只有一条数据,无论过滤与否都没有意义。

但要留神的是,GROUP BY 生成派生表是无奈利用索引筛选的,所以 WHERE 能够利用给字段建设索引优化性能,而 HAVING 针对索引字段不起作用。

总结

聚合函数 + 分组能够实现大部分简略 SQL 需要,在写 SQL 表达式时,须要思考这样的表达式是如何计算的,比方 MAX(c1), c2 是正当的,而 SUM(c1), c2 这个 c2 就是无意义的。

最初记住 WHERE 是 GROUP BY 之前执行的,HAVING 针对组进行筛选。

探讨地址是:精读《SQL 聚合查问》· Issue #401 · ascoders/weekly

如果你想参加探讨,请 点击这里,每周都有新的主题,周末或周一公布。前端精读 – 帮你筛选靠谱的内容。

关注 前端精读微信公众号

<img width=200 src=”https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg”>

版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)

正文完
 0