数据查询语言DQL
数据查询语言 DQL 使用 SELETE
命令进行查询。
SELECT 查询语句
SELECT语句用于从表中选取数据,最简单的方式从某个表查询所有的字段数据:
SELECT * FROM 表名
例如:
mysql> select * from student;
+----------+--------+------+
| id | name | age |
+----------+--------+------+
| 20141224 | 占国慧 | 24 |
| 20141223 | 于殿强 | 24 |
| 20141222 | 杨文彦 | 24 |
| 20141219 | 田明赫 | 25 |
+----------+--------+------+
4 rows in set (0.01 sec)
去重
去重可以通过关键词 DISTINCT
来实现,例如
mysql> select distinct age from student;
+------+
| age |
+------+
| 24 |
| 25 |
+------+
2 rows in set (0.00 sec)
条件查询
条件查询用到 WHERE
关键词来实现。
例如我们想在 student 表中,找到 age 等于 24 的所有信息:
mysql> select * from student where age=24;
+----------+--------+------+
| id | name | age |
+----------+--------+------+
| 20141224 | 占国慧 | 24 |
| 20141223 | 于殿强 | 24 |
| 20141222 | 杨文彦 | 24 |
+----------+--------+------+
3 rows in set (0.00 sec)
除此之外,WHERE
条件子句后面可以有很多判断的运算符,例如 =,>,<,<=,>=,!=
等。
操作符 | 描述 |
---|---|
= | 等于 |
<> | 不等于,在某些版本里,也写为!= |
> (<) | 大于(小于) |
>= (<=) | 大于等于(小于等于) |
BETWEEN | 在某个范围内,BETWEEN ... AND 会选取介于两个值之间的数据范围 |
LIKE | 搜索某种模式 |
IN | WHERE XXX IN (值1, 值2, ...) |
排序
ORDER BY
语句来实现,语法如下:
SELECT * FROM 表名 WHERE 条件 ORDER BY 字段1 DESC|ASC, 字段2 DESC|ASC ...
这里的 DESC
和 ASC
表示按降序排序和升序排序,默认升序排序。ORDER BY
后面可以跟多个字段排序。例如:
mysql> select * from student order by age desc, id asc;
+----------+--------+------+
| id | name | age |
+----------+--------+------+
| 20141219 | 田明赫 | 25 |
| 20141222 | 杨文彦 | 24 |
| 20141223 | 于殿强 | 24 |
| 20141224 | 占国慧 | 24 |
+----------+--------+------+
4 rows in set (0.00 sec)
这里可以看出,当存在多个字段排序时,会先根据第一个字段排序,当第一个字段一样时,再按第二个字段排序。
限制
LIMIT
语句:对于查询后的数据,我们如果只想显示一部分的话,就需要使用 LIMIT
关键词来实现。例如我们只想取3条数据显示:
SELECT * FROM 表名 LIMIT 3;
上述的 LIMIT
是从表的第 0 条开始取的,我们也可以从指定记录开始取,比如从第二条数据开始取,取三条数据:
SELECT * FROM 表名 LIMIT 2,3;
MySQL 也支持语句:
SELECT * FROM 表名 LIMIT 3 OFFSET 0
其中 3
表明每页显示3条结果, OFFSET 0
第 0 条开始显示。
Limit的效率高?
常说的Limit的执行效率高,是对于一种特定条件下来说的:即数据库的数量很大,但是只需要查询一部分数据的情况。 高效率的原理是:避免全表扫描,提高查询效率。
比如:每个用户的email是唯一的,如果用户使用email作为用户名登陆的话,就需要查询出email对应的一条记录。
SELECT * FROM t_user WHERE email=?;
上面的语句实现了查询email对应的一条用户信息,但是由于email这一列没有加索引,会导致全表扫描,效率会很低。
SELECT * FROM t_user WHERE email=? LIMIT 1;
加上LIMIT 1,只要找到了对应的一条记录,就不会继续向下扫描了,效率会大大提高。
Limit的效率低?
在一种情况下,使用 LIMIT
效率低,那就是:只使用 LIMIT
来查询语句,并且偏移量特别大的情况,例如:
语句1:
select * from 表名 limit 150000,1000;
语句2:
select * from 表名 where id>=150000 limit 1000;
语句1为0.2077秒;语句2为0.0063秒。两条语句的时间比是:语句1/语句2=32.968。
比较以上的数据时,我们可以发现采用 WHERE...LIMIT....
性能基本稳定,受偏移量和行数的影响不大,而单纯采用 LIMIT
的话,受偏移量的影响很大,当偏移量大到一定后性能开始大幅下降。不过在数据量不大的情况下,两者的区别不大。所以应当先使用 WHERE
等查询语句,配合 LIMIT
使用,效率才高。
在 SQL 语句中,LIMIT
关键字是最后才用到的。以下条件的出现顺序一般是:where->group by->having-order by->limit
。
聚合函数
下面我们学习一下对记录进行汇总的操作,这类操作主要有:
- 汇总函数:比如求和SUM,统计 COUNT,最值 MAX/MIN等;
GROUP BY
:关键词表示对分类聚合的字段进行分组。HAVING
:关键词表示对分类后的结果再进行条件的过滤。
WHERE
和 HAVING
的用法不一样,WHERE
关键词用在统计之前,对统计前的记录进行过滤,HAVING
关键词则是用在统计之后,对聚合之后的结果进行过滤。因此 WHERE
永远在 HAVING
的前面。
例如,对 student 表的年龄求和:
mysql> select sum(age) from student;
+----------+
| sum(age) |
+----------+
| 97 |
+----------+
1 row in set (0.01 sec)
(由于数据太少,我在student表中已经添加了5条数据)
统计 student 表的数据条数:
mysql> select count(*) from student;
+----------+
| count(1) |
+----------+
| 9 |
+----------+
1 row in set (0.00 sec)
对 student 表按 age 分组:
mysql> select age,count(*) from student group by age;
+------+----------+
| age | count(*) |
+------+----------+
| 24 | 6 |
| 25 | 2 |
| 23 | 1 |
+------+----------+
3 rows in set (0.00 sec)
表连接
当需要同时显示多个表中的字段时,就可以用表连接实现。
内连接:宣称两张表中互相匹配的记录;
外连接:不仅选出匹配的记录,也会选出不匹配的记录;
- 左外连接:筛选出包括左表的记录并且右表没有和它匹配的记录。
- 右外连接:筛选出包括右表的记录并且左表没有和它匹配的记录。
我在 yw1402 数据库中新建了一个 type_job 表。
mysql> select * from type_job;
+------+--------------+
| type | name |
+------+--------------+
| 1 | student |
| 2 | postgraduate |
| 3 | PhD |
| 4 | Overseas |
| 5 | Worker |
| 6 | Professor |
+------+--------------+
6 rows in set (0.00 sec)
然后在 student 表中另加一列 type属性。
mysql> select * from student;
+----------+--------+------+------+
| id | name | age | type |
+----------+--------+------+------+
| 20141224 | 占国慧 | 24 | 1 |
| 20141223 | 于殿强 | 24 | 2 |
| 20141222 | 杨文彦 | 24 | 4 |
| 20141219 | 田明赫 | 25 | 3 |
| 20141225 | 胡j | 23 | 3 |
| 20141226 | 林z | 24 | 2 |
| 20141227 | 孙x | 24 | 3 |
| 20141228 | 唐r | 25 | 5 |
| 20141229 | 张b | 24 | 3 |
| 20148888 | 张三 | 100 | NULL |
+----------+--------+------+------+
10 rows in set (0.00 sec)
下面我们进行左外连接,查询两表中type匹配的 id 和 name;
mysql> select student.name, type_job.name from student left join type_job on student.type=type_job.type;
+--------+--------------+
| name | name |
+--------+--------------+
| 占国慧 | student |
| 于殿强 | postgraduate |
| 杨文彦 | Overseas |
| 田明赫 | PhD |
| 胡j | PhD |
| 林z | postgraduate |
| 孙x | PhD |
| 唐r | Worker |
| 张b | PhD |
| 张三 | NULL |
+--------+--------------+
10 rows in set (0.00 sec)
右连接:
mysql> select student.name, type_job.name from student right join type_job on student.type=type_job.type;
+--------+--------------+
| name | name |
+--------+--------------+
| 占国慧 | student |
| 于殿强 | postgraduate |
| 林z | postgraduate |
| 田明赫 | PhD |
| 胡j | PhD |
| 孙x | PhD |
| 张b | PhD |
| 杨文彦 | Overseas |
| 唐r | Worker |
| NULL | Professor |
+--------+--------------+
10 rows in set (0.00 sec)
子查询
有时候,我们需要的查询条件是另一个 SQL 语句的查询结果,这种查询方式称为子查询。子查询的关键词有 in,not in,=,!=, exists,not exists
等。