《SQL基础教程》+ 《SQL进阶教程》 学习笔记 (2)

注意:MAX/MIN 函数和 SUM/AVG 函数有一点不同,那就是 SUM/ AVG 函数只能对数值类型的列使用,而 MAX/MIN 函数原则上可以适用于任何数据类型的列。

(2)注意 NULL

聚合函数普遍会将 NULL 排除在外( COUNT 函数例外),具体如下:

1、COUNT 函数的结果根据参数的不同而不同。COUNT(*)会得到包含 NULL 的数据行数,而 COUINT(<列名>) 会得到不包含 NULL的数据行数。

SELECT COUNT(DISTINCT <列名>) 可以得到不包含 NULL 且 不重复的数据行数。

2、SUM 函数将 NULL 忽略,也可理解成视为 0。

3、AVG 函数将 NULL 忽略,即不参与分母也不参与分子。

2、对表进行分组 —— GROUP BY

GROUP BY 一般习惯跟聚合函数搭配使用。

(1)进阶 - GROUP BY 与 数学中的 类

它们全都是非空集合。

所有子集的并集等于划分之前的集合。

任何两个子集之间都没有交集。

在数学(群论)中,满足以上3 个性质的各子集称为“类”(partition),将原来的集合分割成若干个类的操作称为“分类”。

所以 GROUP BY 和 下面要介绍的 PARTITION BY 都是用来划分 类 的函数。

问:去重用 GROUP BY 还是 DISTINCT ?

如果用了 GROUP BY 却没用聚合函数,多半是为了去重,但有 DISTINCT 呀:

-- 1、DISTINCT SELECT DISTINCT "product_type" FROM "Product" -- 2、GROUP BY SELECT "product_type" FROM "Product" GROUP BY "product_type"

注意:上面两种结果,都会保留 NULL 行。

答:用 DISTINCT。可读性优先。

常见错误 1 一一 在 SELECT 子句中书写了多余的列

原因:多余的列并没有被聚合,当然无法显示。

解决方案:SELECT 子句中只能存在以下三种元素:

常数

聚合函数

GROUP BY 子句中指定的列名(也就是聚合键)

常见错误 2 一一 在 GROUP BY 子句中写了在 SELECT 里指定的列的别名

原因:跟执行顺序有关:FROM→ WHERE→ GROUP BY→ SELECT

解决方案:其实 PostgreSQL 支持这种写法。但推荐为了遵循 标准 SQL ,尽量不要这样写。

常见错误 3 一一 在 WHERE 子句中使用聚合函数

例子:

-- 错误1: SELECT "product_type", COUNT(*) FROM "Product" WHERE COUNT(*) = 2 GROUP BY "product_type" -- 错误2: SELECT "product_type", COUNT(*) FROM "Product" GROUP BY "product_type" WHERE COUNT(*) = 2 -- 正确: SELECT "product_type", COUNT(*) FROM "Product" GROUP BY "product_type" HAVING COUNT(*) = 2

原因:WHERE 子句不可以使用聚合函数,因为他针对的是行而不是组。

解决方案:请用下面会介绍的 HAVING 子句代替这里的 WHERE。

3、为聚合结果指定条件 —— HAVING (1)WHERE vs. HAVING

WHERE 子句 —— 指定行条件

HAVING 子句 —— 指定组条件

例子:

-- WHERE 子句 SELECT * FROM "Product" WHERE "product_type" = '体育' -- HAVING 子句 SELECT "product_type", COUNT(*) FROM "Product" GROUP BY "product_type" HAVING COUNT(*) = 2 -- WHERE + HAVING 子句 SELECT "product_type", COUNT(*) FROM "Product" GROUP BY "product_type" WHERE "product_price" > 10 HAVING COUNT(*) = 2 (2)HAVING 也可不加 GROUP BY

HAVING 不加 GROUP BY(也可认为是对空字段进行了 GROUP BY 操作),整张表会被视为一个组。

SELECT '存在缺失的编号' AS gap FROM "Product" HAVING COUNT(*) <> MAX("product_id");

这种情况下,就不能在SELECT 子句里引用原来的表里的列了,要么就得像示例里一样使用常量,要么就得像 SELECT COUNT(*) 这样使用聚合函数

类似于使用窗口函数时不指定 PARTITION BY 子句,就是把整个表当作一个窗口来处理。

(3)对聚合键的筛选是放 WHERE 还是 HAVING ?

例子:

-- 1、放在 HAVING SELECT "product_type", COUNT (*) FROM "Product" GROUP BY "product_type" HAVING "product_type" <> '衣服' -- 2、放在 WHERE SELECT "product_type", COUNT (*) FROM "Product" WHERE "product_type" <> '衣服' GROUP BY "product_type"

结论:放在 WHERE 子句。(能写在 WHERE 子句里的条件就不要写在 HAVING 子句里)

理由:

1、通过 WHERE 子句指定条件时,由于排序之前就对数据进行了过滤,因此能够减少排序的数据量。但 HAVING 子句是在排序之后オ对数据进行分组的,因此与在 WHERE 子句中指定条件比起来,需要排序的数据量就会多得多。

2、可以对 WIHERE 子句指定条件所对应的列创建索引,这样也可以大幅提高处理速度。

GROUP BY 生成的是派生表,HAVING 无法使用索引。

4、对查询结果进行排序 —— ORDER BY (1)用法

SELECT 语句末尾添加 ORDER BY 子句来明确指定排列顺序。

select * FROM "Activity" ORDER BY "id" DESC

ASC —— ascendent(上升的)【省略即默认】

DESC —— descendent(下降的)

执行顺序:FROM→ WHERE→ GROUP BY→ HAVING→ SELECT→ ORDER BY

注意:ORDER BY 子句中也可以使用聚合函数,跟 SELECT 里一样。

(2)注意 NULL

排序键中包含 NULL 时,会在开头或末尾进行汇总。究竟是在开头显示还是在末尾显示,并没有特殊规定。每家 DBMS 可能不一样。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygdwg.html