数据查询语言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 ...

这里的 DESCASC 表示按降序排序和升序排序,默认升序排序。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:关键词表示对分类后的结果再进行条件的过滤。

WHEREHAVING 的用法不一样,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 等。