总结一些sql相关的易错知识点,大部分结论也适用于其他的数据库。
测试环境:Mysql 5.7
目录
1、左上角的点(间隔号)表示对列名做标注,而普通的单引号则表示字符串
4、null参与的逻辑运算,除了“真”、“假”两种结果外,可能还会出现另一种情况:“不确定”
7、NULL在order by时可能会被放到末尾,也可能会被放到开头,不参与排序
10、mysql中开始事务是 start transaction或者begin
11、mysql在排序字符型的列时,使用的是字典序('2' > 10'')
12、DISTINCT也可以放在聚合函数里 count(DISTINCT 列名)
测试数据
create table sale(
id int primary key auto_increment,
productName varchar(20),
type varchar(10),
price int,
description varchar(200)
)
insert into sale(productName, type, price, description) values('苹果', '水果', 8, '不太好吃');
insert into sale(productName, type, price, description) values('外套', '衣服', 200, '很好看');
insert into sale(productName, type, price, description) values('短袖', '衣服', 120, null);
insert into sale(productName, type, price, description) values('电脑', '电子产品', 8000, '性能比较差');
insert into sale(productName, type, price, description) values('手机', '电子产品', 3000, null);
insert into sale(productName, type, price, description) values('橘子', '水果', 6, null);
insert into sale(productName, type, price, description) values('pad', '电子产品', 5000, null);
insert into sale(productName, type, price, description) values('菠萝', '水果', 20, '太酸了');
insert into sale(productName, type, price, description) values('羽绒服', '衣服', 800, null);
insert into sale(productName, type, price, description) values('西瓜', '水果', 18, null);
1、左上角的点(间隔号)表示对列名做标注,而普通的单引号则表示字符串
说明:左上角的点指的是和波浪号在一个格子的符号
验证:
间隔号
select `productName` from sale;
结果:
单引号
select 'productName' from sale;
结果:
2、NULL和任何类型的数值做计算,结果都是null
NULL在数据库中比较特殊,处理起来相对比较麻烦。
验证:
mysql> select null + 1;
+----------+
| null + 1 |
+----------+
| NULL |
+----------+
1 row in set (0.02 sec)
mysql> select 1 + 1;
+-------+
| 1 + 1 |
+-------+
| 2 |
+-------+
1 row in set (0.03 sec)
3、不能对NULL使用比较运算符
对NULL进行比较运算是没有意义的。
验证:
mysql> select null < 1;
+----------+
| null < 1 |
+----------+
| NULL |
+----------+
1 row in set (0.02 sec)
mysql> select 2 < 1;
+-------+
| 2 < 1 |
+-------+
| 0 |
+-------+
1 row in set (0.05 sec)
4、null参与的逻辑运算,除了“真”、“假”两种结果外,可能还会出现另一种情况:“不确定”
首先要明确以前,在mysql中,“真” 通常用1表示,“假” 用0表示,“不确定” 通常用null表示。
mysql> select true and null;
+---------------+
| true and null |
+---------------+
| NULL |
+---------------+
1 row in set (0.01 sec)
mysql> select false and null;
+----------------+
| false and null |
+----------------+
| 0 |
+----------------+
1 row in set (0.01 sec)
可以看到,有null参与的运算,其结果需要格外注意。
两种运算的真值表如下:
AND运算
P | Q | P AND Q |
---|---|---|
真 | 真 | 真 |
真 | 假 | 假 |
真 | 不确定 | 不确定 |
假 | 真 | 假 |
假 | 假 | 假 |
假 | 不确定 | 假 |
不确定 | 真 | 不确定 |
不确定 | 假 | 假 |
不确定 | 不确定 | 不确定 |
OR运算
P | Q | P OR Q |
---|---|---|
真 | 真 | 真 |
真 | 假 | 真 |
真 | 不确定 | 真 |
假 | 真 | 真 |
假 | 假 | 假 |
假 | 不确定 | 不确定 |
不确定 | 真 | 真 |
不确定 | 假 | 不确定 |
不确定 | 不确定 | 不确定 |
5、聚合函数在运算时会忽略NULL值,但是COUNT除外
要注意,只有count(*)是统计NULL的,如果是count(列名)同样也不会把NULL算在内。
把测试数据第一行的price改为null。
验证:
mysql> select sum(price) from sale;
+------------+
| sum(price) |
+------------+
| 17164 |
+------------+
1 row in set (0.02 sec)
mysql> select count(price) from sale;
+--------------+
| count(price) |
+--------------+
| 9 |
+--------------+
1 row in set (0.08 sec)
mysql> select count(*) from sale;
+----------+
| count(*) |
+----------+
| 10 |
+----------+
1 row in set (0.07 sec)
6、NULL在group by的时候,会被单独分在一组
验证:
mysql> select description, count(1) from sale group by description;
+-------------+----------+
| description | count(1) |
+-------------+----------+
| NULL | 6 |
| 不太好吃 | 1 |
| 太酸了 | 1 |
| 很好看 | 1 |
| 性能比较差 | 1 |
+-------------+----------+
5 rows in set (0.04 sec)
7、NULL在order by时可能会被放到末尾,也可能会被放到开头,不参与排序
验证:
mysql> select * from sale order by price;
+----+-------------+----------+-------+-------------+
| id | productName | type | price | description |
+----+-------------+----------+-------+-------------+
| 1 | 苹果 | 水果 | NULL | 不太好吃 |
| 6 | 橘子 | 水果 | 6 | NULL |
| 10 | 西瓜 | 水果 | 18 | NULL |
| 8 | 菠萝 | 水果 | 20 | 太酸了 |
| 3 | 短袖 | 衣服 | 120 | NULL |
| 2 | 外套 | 衣服 | 200 | 很好看 |
| 9 | 羽绒服 | 衣服 | 800 | NULL |
| 5 | 手机 | 电子产品 | 3000 | NULL |
| 7 | pad | 电子产品 | 5000 | NULL |
| 4 | 电脑 | 电子产品 | 8000 | 性能比较差 |
+----+-------------+----------+-------+-------------+
10 rows in set (0.06 sec)
8、coalesce函数可以对NULL值做特殊处理
通常用在select后面
coalesce(param1, param2, param3......) 参数的个数是可变得,返回第一个不为NULL的参数。
验证:
mysql> select productName, coalesce(description, '未知') from sale;
+-------------+-------------------------------+
| productName | coalesce(description, '未知') |
+-------------+-------------------------------+
| 苹果 | 不太好吃 |
| 外套 | 很好看 |
| 短袖 | 未知 |
| 电脑 | 性能比较差 |
| 手机 | 未知 |
| 橘子 | 未知 |
| pad | 未知 |
| 菠萝 | 太酸了 |
| 羽绒服 | 未知 |
| 西瓜 | 未知 |
+-------------+-------------------------------+
10 rows in set (0.09 sec)
9、 NOT IN 语法对NULL无效
判断某个值是不是NULL,要用 IS NULL或者IS NOT NULL来判断。
所谓“无效”,指两方面
一是:结果集中不会出现NULL相关的列。
二是:in列表中如果出现为null的值,那么结果集肯定是空。
验证
mysql> select productName, description from sale where description not in('太酸了');
+-------------+-------------+
| productName | description |
+-------------+-------------+
| 苹果 | 不太好吃 |
| 外套 | 很好看 |
| 电脑 | 性能比较差 |
+-------------+-------------+
3 rows in set (0.07 sec)
mysql> select productName, description from sale where description not in(null);
Empty set
mysql> select productName, description from sale where description not in('太酸了', null);
Empty set
10、mysql中开始事务是 start transaction或者begin
mysql中开始事务可以用下面两种方式
1、begin;
2、start transaction
不能用 begin transaction;
begin transaction:
start:
begin:
11、mysql在排序字符型的列时,使用的是字典序('2' > 10'')
这一点在某些场合下,容易被误用,比如某个列都是数字,但是类型是varchar,如果把他当做数字来排序时,可能会出现意料之外的结果。
添加几条数据。
验证:
mysql> select * from sale order by description asc;
+----+-------------+----------+-------+-------------+
| id | productName | type | price | description |
+----+-------------+----------+-------+-------------+
| 9 | 羽绒服 | 衣服 | 800 | NULL |
| 10 | 西瓜 | 水果 | 18 | NULL |
| 3 | 短袖 | 衣服 | 120 | 1 |
| 6 | 橘子 | 水果 | 6 | 10 |
| 5 | 手机 | 电子产品 | 3000 | 2 |
| 7 | pad | 电子产品 | 5000 | 20 |
| 1 | 苹果 | 水果 | NULL | 不太好吃 |
| 8 | 菠萝 | 水果 | 20 | 太酸了 |
| 2 | 外套 | 衣服 | 200 | 很好看 |
| 4 | 电脑 | 电子产品 | 8000 | 性能比较差 |
+----+-------------+----------+-------+-------------+
可以看到,升序时, “2”排在了“10”的后面,符合字典序,但不符合数字处理的逻辑。
所以说,如果确定某个列是数值型,那么在设计表的时候还是尽量不要用字符型。
12、DISTINCT也可以放在聚合函数里 count(DISTINCT 列名)
验证:
mysql> select count(type) from sale;
+-------------+
| count(type) |
+-------------+
| 10 |
+-------------+
1 row in set (0.06 sec)
mysql> select count( distinct type) from sale;
+-----------------------+
| count( distinct type) |
+-----------------------+
| 3 |
+-----------------------+
1 row in set (0.07 sec)
小知识:mysql中distinct 是一个函数,但是有语法糖,可以不用加括号。
mysql> select distinct(type) from sale;
+----------+
| type |
+----------+
| 水果 |
| 衣服 |
| 电子产品 |
+----------+
3 rows in set (0.06 sec)
mysql> select distinct type from sale;
+----------+
| type |
+----------+
| 水果 |
| 衣服 |
| 电子产品 |
+----------+
3 rows in set (0.07 sec)
13、关联子查询的用法
有时候会遇到一些统计信息,出现“高于平均水平”或者“低于平均水平”等字样,就需要用到关联子查询。
比如我想查询出价格高于平均水平的商品以及他的数量,可以这么做
mysql> select productName, price from sale s1 where price > (select avg(price) from sale s2 where s1.type = s2.type group by s2.type);
+-------------+-------+
| productName | price |
+-------------+-------+
| 电脑 | 8000 |
| 菠萝 | 20 |
| 羽绒服 | 800 |
| 西瓜 | 18 |
+-------------+-------+
4 rows in set (0.02 sec)
参考《SQL 基础教程》,如有错误,欢迎指正。