《SQL基础教程》阅读笔记4
子句书写顺序:
SELECT->FROM ->WHERE-> GROUP BY ->HAVING ->ORDER BY
聚合与排序
对表进行聚合查询
聚合函数
用于汇总的函数称为聚合函数,所谓聚合就是将多行汇总为一行
5个常用的聚合函数
- COUNT 计算表中的记录数
- SUM 计算表中数值列中数据的合计值
- AVG 计算表中数值列中数据的平均值
- MAX 计算表中数值列中数据的最大值
- MIN 计算表中数值列中数据的最小值
示例(COUNT):
mysql> SELECT COUNT(*) FROM Product;
+----------+
| COUNT(*) |
+----------+
| 8 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(purchase_price) FROM Product;
+-----------------------+
| COUNT(purchase_price) |
+-----------------------+
| 6 |
+-----------------------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*), COUNT(purchase_price) FROM Product;
+----------+-----------------------+
| COUNT(*) | COUNT(purchase_price) |
+----------+-----------------------+
| 8 | 6 |
+----------+-----------------------+
1 row in set (0.00 sec)
说明:
COUNT(*) 代表的是计算所有的行数,就算有一行所有的值都是NULL,还是会被计算在内
COUNT(列名) 代表的是这一列中所有不是NULL的行数
示例(SUM):
说明:SUM 会忽略掉所有的NULL,而不会将NULL加上去(所有NULL参与的运算的结果都是NULL),这里可以认为将NULL看作0来计算
mysql> SELECT SUM(purchase_price), SUM(sale_price) FROM Product;
+---------------------+-----------------+
| SUM(purchase_price) | SUM(sale_price) |
+---------------------+-----------------+
| 12210 | 16780 |
+---------------------+-----------------+
1 row in set (0.00 sec)
示例(AVG)
可以将NULL看作是0来计算,但是本质上不是这么做的
AVG做的就是将SUM的值/值的个数
mysql> SELECT AVG(purchase_price), AVG(sale_price) FROM Product;
+---------------------+-----------------+
| AVG(purchase_price) | AVG(sale_price) |
+---------------------+-----------------+
| 2035.0000 | 2097.5000 |
+---------------------+-----------------+
1 row in set (0.00 sec)
示例(MAX 和 MIN)
mysql> SELECT MAX(regist_date), MIN(regist_date) FROM Product;
+------------------+------------------+
| MAX(regist_date) | MIN(regist_date) |
+------------------+------------------+
| 2009-11-11 | 2008-04-28 |
+------------------+------------------+
1 row in set (0.01 sec)
使用聚合函数删除重复值(关键字 DISTINCT)
回顾一下:使用count函数
如果count(单列列名) 返回的是该列非NULL的行数
如果count(*) 返回的是所有的行数
如果想要获得没有重复值的行数,则需要DISTINCT关键字
mysql> SELECT COUNT(DISTINCT product_type) FROM Product;
+------------------------------+
| COUNT(DISTINCT product_type) |
+------------------------------+
| 3 |
+------------------------------+
1 row in set (0.00 sec)
对表进行分组
mysql> SELECT product_type, COUNT(*) FROM Product GROUP BY product_type;
+--------------+----------+
| product_type | COUNT(*) |
+--------------+----------+
| 办公用品 | 2 |
| 厨房用具 | 4 |
| 衣服 | 2 |
+--------------+----------+
3 rows in set (0.00 sec)
说明:
这里的意思是,打印 product_type 和 count 的值,这些值来自于根据product_type 分的组中,也就是说这里面分了三组,分别是 办公用具、厨房用具、衣服 ,count则是分别计算每一组出现的次数
而且,如果有NULL的话,NULL会被单独算一组
加入where子句
mysql> SELECT product_type, COUNT(*) FROM Product WHERE regist_date = '2009-09-20' GROUP BY product_type;
+--------------+----------+
| product_type | COUNT(*) |
+--------------+----------+
| 厨房用具 | 2 |
| 衣服 | 1 |
+--------------+----------+
2 rows in set (0.00 sec)
说明:先找到时间是2009-09-20的行,然后按照product_type 分的类,办公用品这一类没有这个时间注册的,因此没有这一项,计数时候,厨房用品这一天的有2件因此count的值为2
常见错误:
- SELECT col1, col2 FROM product GROUP BY col1;
这种形式是允许的,因为,比如col1 代表时间,col2 代表产品种类,可能一个时间有多个产品被登记,那么就会导致混乱,因此这种形式是不被允许的 - GROUP BY 语句中使用别名:
SELECT col1 AS name1 FROM product GROUP BY name1;
这是由于内部的执行顺序导致的,在进行到分组时候,它还不知道别名是什么。但是这个分数据库管理系统,比如笔者用的Mysql就不会导致错误。但是这不是标准的sql语句 - 认为GROUP BY输出的结果是排好序的:
实际上其输出结果是随机的,如果想要排序,需要进行指定 - 在WHERE 子句中使用聚合函数:
SELECT product_type, COUNT(*)
FROM product
WHERE COUNT(*) = 2
GROUP BY product_type;
这种写法是错误的。实际上想要达到效果,应该使用having 子句
只有SELECT 、HAVING、ORDER BY子句可以使用聚合函数
此外:
可以注意到:
SELECT DISTINCT product_type FROM product;
和
SELECT product_type FROM product GROUP BY product_type;
得到的效果是一样的
为聚合结果指定条件
WHERE 能够指定的是行条件,而HAVING 则是可以指定组条件,因此HAVING 子句可以使用聚合函数
mysql> SELECT product_type, COUNT(*) FROM Product GROUP BY product_type HAVING COUNt(*)=2;
+--------------+----------+
| product_type | COUNT(*) |
+--------------+----------+
| 办公用品 | 2 |
| 衣服 | 2 |
+--------------+----------+
2 rows in set (0.00 sec)
说明:
表中根据product_type 分类,但是只选择那些count值为2 的组
WHERE是先将满足条件的行挑出来,然后再分组
而HAVING 是先分组然后再将合适的组挑出来,因此HAVING只能是组的条件,行条件是不可以的。但是,由于分组是根据一个列来分组,那么HAVING 可以使用这个列的条件
即:
SELECT col1 FROM table GROUP BY col1 HAVING col1 = col1_element1;
但是想要这种情况的话 WHERE 也可以做到,甚至来说,更加推荐用WHERE
对查询结果进行排序
ORDER BY 子句
mysql> SELECT product_type, product_name FROM Product ORDER BY sale_price;
+--------------+--------------+
| product_type | product_name |
+--------------+--------------+
| 办公用品 | 圆珠笔 |
| 办公用品 | 打孔机 |
| 厨房用具 | 叉子 |
| 厨房用具 | 擦菜板 |
| 衣服 | T恤衫 |
| 厨房用具 | 菜刀 |
| 衣服 | 运动T恤 |
| 厨房用具 | 高压锅 |
+--------------+--------------+
8 rows in set (0.00 sec)
mysql> SELECT product_type, product_name FROM Product ORDER BY sale_price DESC;
+--------------+--------------+
| product_type | product_name |
+--------------+--------------+
| 厨房用具 | 高压锅 |
| 衣服 | 运动T恤 |
| 厨房用具 | 菜刀 |
| 衣服 | T恤衫 |
| 厨房用具 | 擦菜板 |
| 办公用品 | 打孔机 |
| 厨房用具 | 叉子 |
| 办公用品 | 圆珠笔 |
+--------------+--------------+
8 rows in set (0.00 sec)
mysql> SELECT product_type, product_name FROM Product ORDER BY sale_price DESC, product_id;
+--------------+--------------+
| product_type | product_name |
+--------------+--------------+
| 厨房用具 | 高压锅 |
| 衣服 | 运动T恤 |
| 厨房用具 | 菜刀 |
| 衣服 | T恤衫 |
| 厨房用具 | 擦菜板 |
| 办公用品 | 打孔机 |
| 厨房用具 | 叉子 |
| 办公用品 | 圆珠笔 |
+--------------+--------------+
8 rows in set (0.00 sec)
说明:
- 排序键可以使用别名
- 可以使用聚合函数
- 可以用数字来代指SELECT 子句中第几个元素
SELECT col1, col2 ,col3 FROM table ORDER BY 2 DESC , 1;
代表 按 col2 的降序排,按col1 的升序排。但是不推荐使用,不易于使用