第7章、简单查询

标签: MySQL是怎样使用的新版


到现在为止,我们已经掌握了数据库的创建、选择和删除语句,表的创建、修改和删除语句以及一些简单的查询和插入记录的语句。不过这些只不过是一个空架子,对于使用MySQL的我们来说,平时使用频率最高的还是查询功能 —— 就是按照我们给定的要求将数据给查出来。从本章开始就要唠叨各种让人眼花缭乱的查询方式了,认真看,仔细看,滴点儿莎普爱思拿抹布擦擦眼继续看!这些东西真的非常重要!

准备工作

话说从本章开始的主题是查询数据,所以先得确定一下查哪个表的数据吧,确定了要查哪个表之后该表中先得有数据吧,要不查个毛线呀~ 所以我们先得做点准备工作,也就是确定使用哪个表做示例以及往表里填点数据。

用哪个表

为简单起见,我们就复用之前在数据库xiaohaizi下边创建的学生信息表student_info和学生成绩表student_score,你可能有点忘了这两个表长啥样了,我们先把两个表的结构回顾一下:

学生基本信息表的结构

  1. CREATE TABLE student_info (
  2. number INT PRIMARY KEY,
  3. name VARCHAR(5),
  4. sex ENUM('男', '女'),
  5. id_number CHAR(18),
  6. department VARCHAR(30),
  7. major VARCHAR(30),
  8. enrollment_time DATE,
  9. UNIQUE KEY (id_number)
  10. );

学生成绩表的结构

  1. CREATE TABLE student_score (
  2. number INT,
  3. subject VARCHAR(30),
  4. score TINYINT,
  5. PRIMARY KEY (number, subject),
  6. CONSTRAINT FOREIGN KEY(number) REFERENCES student_info(number)
  7. );

为表填入数据

我们给这两个表插入一些数据:

  1. mysql> INSERT INTO student_info(number, name, sex, id_number, department, major, enrollment_time) VALUES
  2. -> (20180101, '杜子腾', '男', '158177199901044792', '计算机学院', '计算机科学与工程', '2018-09-01'),
  3. -> (20180102, '杜琦燕', '女', '151008199801178529', '计算机学院', '计算机科学与工程', '2018-09-01'),
  4. -> (20180103, '范统', '男', '17156319980116959X', '计算机学院', '软件工程', '2018-09-01'),
  5. -> (20180104, '史珍香', '女', '141992199701078600', '计算机学院', '软件工程', '2018-09-01'),
  6. -> (20180105, '范剑', '男', '181048199308156368', '航天学院', '飞行器设计', '2018-09-01'),
  7. -> (20180106, '朱逸群', '男', '197995199501078445', '航天学院', '电子信息', '2018-09-01');
  8. Query OK, 6 rows affected (0.01 sec)
  9. Records: 6 Duplicates: 0 Warnings: 0
  10. mysql> INSERT INTO student_score (number, subject, score) VALUES
  11. -> (20180101, '母猪的产后护理', 78),
  12. -> (20180101, '论萨达姆的战争准备', 88),
  13. -> (20180102, '母猪的产后护理', 100),
  14. -> (20180102, '论萨达姆的战争准备', 98),
  15. -> (20180103, '母猪的产后护理', 59),
  16. -> (20180103, '论萨达姆的战争准备', 61),
  17. -> (20180104, '母猪的产后护理', 55),
  18. -> (20180104, '论萨达姆的战争准备', 46);
  19. Query OK, 8 rows affected (0.00 sec)
  20. Records: 8 Duplicates: 0 Warnings: 0
  21. mysql>

现在这两个表中的数据就如下所示了:

student_info表

number name sex id_number department major enrollment_time
20180101 杜子腾 158177199901044792 计算机学院 计算机科学与工程 2018-09-01
20180102 杜琦燕 151008199801178529 计算机学院 计算机科学与工程 2018-09-01
20180103 范统 17156319980116959X 计算机学院 软件工程 2018-09-01
20180104 史珍香 141992199701078600 计算机学院 软件工程 2018-09-01
20180105 范剑 181048200008156368 航天学院 飞行器设计 2018-09-01
20180106 朱逸群 197995199801078445 航天学院 电子信息 2018-09-01

student_score表

number subject score
20180101 母猪的产后护理 78
20180101 论萨达姆的战争准备 88
20180102 母猪的产后护理 100
20180102 论萨达姆的战争准备 98
20180103 母猪的产后护理 59
20180103 论萨达姆的战争准备 61
20180104 母猪的产后护理 55
20180104 论萨达姆的战争准备 46

好了,表的填充工作也已经做完了~ 终于可以开始查询数据了!

查询单个列

查看某个表中的某一列的数据的通用格式是这样:

  1. SELECT 列名 FROM 表名;

也就是说把需要查询的列名放到单词SELECT后边就好了,比如查看student_info表中的number列的数据可以这么写:

  1. mysql> SELECT number FROM student_info;
  2. +----------+
  3. | number |
  4. +----------+
  5. | 20180104 |
  6. | 20180102 |
  7. | 20180101 |
  8. | 20180103 |
  9. | 20180105 |
  10. | 20180106 |
  11. +----------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

可以看到查询结构中就把所有记录的number列都展示了出来,我们有时候也把这个结果称之为结果集

小贴士: 你可能发现结果集中的数据并不是按照我们number列值的大小排序的,我们稍后就会说到如何指定结果集中数据的排序方式,稍安勿躁。

列的别名

我们也可以为结果集中的列重新定义一个别名,命令格式如下:

  1. SELECT 列名 [AS] 列的别名 FROM 表名;

我们看到AS被加了个中括号,意味着可有可无,没有AS的话,列名和列的别名之间用空白字符隔开就好了。比如我们想给number列起个别名,可以使用下边这两种方式之一:

  • 方式一

    1. SELECT number AS 学号 FROM student_info;
  • 方式二:

    1. SELECT number 学号 FROM student_info;

我们执行一下:

  1. mysql> SELECT number AS 学号 FROM student_info;
  2. +----------+
  3. | 学号 |
  4. +----------+
  5. | 20180104 |
  6. | 20180102 |
  7. | 20180101 |
  8. | 20180103 |
  9. | 20180105 |
  10. | 20180106 |
  11. +----------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

看到黑框框里的结果集中显示的列名就不再是number,而是我们刚刚定义的别名学号了。不过需要注意的是:别名只是在本次查询的到的结果集中展示,而不会改变真实表中的列名。下一次查询中你对number列取其他的别名也可以,比如这样:

  1. mysql> SELECT number xuehao FROM student_info;
  2. +----------+
  3. | xuehao |
  4. +----------+
  5. | 20180104 |
  6. | 20180102 |
  7. | 20180101 |
  8. | 20180103 |
  9. | 20180105 |
  10. | 20180106 |
  11. +----------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

这次输出的列名就是另一个别名xuehao了。

查询多个列

如果想查询多个列的数据,可以在SELECT后边写多个列名,用逗号,分隔开就好:

  1. SELECT 列名1, 列名2, ... 列名n FROM 表名;

我们把SELECT语句后边跟随的多个列统称为查询列表,需要注意的是,查询列表中的列名可以按任意顺序摆放,结果集将按照我们指定的列名顺序显示。比如我们查询student_info中的多个列:

  1. mysql> SELECT number, name, id_number, major FROM student_info;
  2. +----------+-----------+--------------------+--------------------------+
  3. | number | name | id_number | major |
  4. +----------+-----------+--------------------+--------------------------+
  5. | 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
  6. | 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
  7. | 20180103 | 范统 | 17156319980116959X | 软件工程 |
  8. | 20180104 | 史珍香 | 141992199701078600 | 软件工程 |
  9. | 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
  10. | 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
  11. +----------+-----------+--------------------+--------------------------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

本例中的查询列表就是number,name,id_number,major,所以结果集中列的顺序就按照这个顺序来显示。当然,我们也可以用别名来输出这些数据:

  1. mysql> SELECT number AS 学号, name AS 姓名, id_number AS 身份证号, major AS 专业 FROM student_info;
  2. +----------+-----------+--------------------+--------------------------+
  3. | 学号 | 姓名 | 身份证号 | 专业 |
  4. +----------+-----------+--------------------+--------------------------+
  5. | 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
  6. | 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
  7. | 20180103 | 范统 | 17156319980116959X | 软件工程 |
  8. | 20180104 | 史珍香 | 141992199701078600 | 软件工程 |
  9. | 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
  10. | 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
  11. +----------+-----------+--------------------+--------------------------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

如果你乐意,同一个列可以在查询列表处重复出现(虽然这通常没什么卵用),比如这样:

  1. mysql> SELECT number, number, number FROM student_info;
  2. +----------+----------+----------+
  3. | number | number | number |
  4. +----------+----------+----------+
  5. | 20180104 | 20180104 | 20180104 |
  6. | 20180102 | 20180102 | 20180102 |
  7. | 20180101 | 20180101 | 20180101 |
  8. | 20180103 | 20180103 | 20180103 |
  9. | 20180105 | 20180105 | 20180105 |
  10. | 20180106 | 20180106 | 20180106 |
  11. +----------+----------+----------+
  12. 6 rows in set (0.00 sec)
  13. mysql>

查询所有列

如果需要把记录中的所有列都查出来,MySQL也提供一个省事儿的办法,我们之前也介绍过,就是直接用星号*来表示要查询的东西,就像这样:

  1. SELECT * FROM 表名;

这个命令我们之前看过了,就不多唠叨了。不过需要注意的是,除非你确实需要表中的每个列,否则一般最好别使用星号*来查询所有列,虽然星号*看起来很方便,不用明确列出所需的列,但是查询不需要的列通常会降低性能。

查询结果去重

去除单列的重复结果

有的时候我们查询某个列的数据时会有一些重复的结果,比如我们查询一下student_info表的学院信息:

  1. mysql> SELECT department FROM student_info;
  2. +-----------------+
  3. | department |
  4. +-----------------+
  5. | 计算机学院 |
  6. | 计算机学院 |
  7. | 计算机学院 |
  8. | 计算机学院 |
  9. | 航天学院 |
  10. | 航天学院 |
  11. +-----------------+
  12. 6 rows in set (0.00 sec)

因为表里有6条记录,所以给我们返回了6条结果。但是其实好多都是重复的结果,如果我们想去除重复结果的话,可以将DISTINCT放在被查询的列前边,就是这样:

  1. SELECT DISTINCT 列名 FROM 表名;

我们对学院信息做一下去重处理:

  1. mysql> SELECT DISTINCT department FROM student_info;
  2. +-----------------+
  3. | department |
  4. +-----------------+
  5. | 计算机学院 |
  6. | 航天学院 |
  7. +-----------------+
  8. 2 rows in set (0.00 sec)

看到结果集中就只剩下不重复的信息了。

去除多列的重复结果

对于查询多列的情况,两条结果重复的意思是:两条结果的每一个列中的值都相同。比如查询学院和专业信息:

  1. mysql> SELECT department, major FROM student_info;
  2. +-----------------+--------------------------+
  3. | department | major |
  4. +-----------------+--------------------------+
  5. | 计算机学院 | 计算机科学与工程 |
  6. | 计算机学院 | 计算机科学与工程 |
  7. | 计算机学院 | 软件工程 |
  8. | 计算机学院 | 软件工程 |
  9. | 航天学院 | 飞行器设计 |
  10. | 航天学院 | 电子信息 |
  11. +-----------------+--------------------------+
  12. 6 rows in set (0.00 sec)

查询结果中第1、2行记录中的departmentmajor列都相同,所以这两条记录就是重复的,同理,第3、4行也是重复的。如果我们想对多列查询的结果去重的话,可以直接把DISTINCT放在被查询的列的最前边:

  1. SELECT DISTINCT 列名1, 列名2, ... 列名n FROM 表名;

比如这样:

  1. mysql> SELECT DISTINCT department, major FROM student_info;
  2. +-----------------+--------------------------+
  3. | department | major |
  4. +-----------------+--------------------------+
  5. | 计算机学院 | 计算机科学与工程 |
  6. | 计算机学院 | 软件工程 |
  7. | 航天学院 | 飞行器设计 |
  8. | 航天学院 | 电子信息 |
  9. +-----------------+--------------------------+
  10. 4 rows in set (0.00 sec)
  11. mysql>

限制查询结果条数

有时候查询结果的条数会很多,都显示出来可能会撑爆屏幕~ 所以MySQL给我们提供了一种限制结果集中的记录条数的方式,就是在查询语句的末尾使用这样的语法:

  1. LIMIT 开始行, 限制条数;

开始行指的是我们想从第几行数据开始查询,限制条数是结果集中最多包含多少条记录。

小贴士: 在生活中通常都是从1开始计数的,而在计算机中都是从0开始计数的,所以我们平时所说的第1条记录在计算机中算是第0条。比如`student_info`表里的6条记录在计算机中依次表示为:第0条、第1条、第2条、第3条、第4条、第5条。

比如我们查询一下student_info表,从第0条记录开始,最多查询2条记录可以这么写:

  1. mysql> SELECT number, name, id_number, major FROM student_info LIMIT 0, 2;
  2. +----------+-----------+--------------------+--------------------------+
  3. | number | name | id_number | major |
  4. +----------+-----------+--------------------+--------------------------+
  5. | 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
  6. | 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
  7. +----------+-----------+--------------------+--------------------------+
  8. 2 rows in set (0.00 sec)
  9. mysql>

如果指定的开始行大于结果中的行数,那查询结果就什么都没有:

  1. mysql> SELECT number, name, id_number, major FROM student_info LIMIT 6, 2;
  2. Empty set (0.00 sec)
  3. mysql>

如果查询的结果条数不超过限制条数,那就可以全部显式出来:

  1. mysql> SELECT number, name, id_number, major FROM student_info LIMIT 4, 3;
  2. +----------+-----------+--------------------+-----------------+
  3. | number | name | id_number | major |
  4. +----------+-----------+--------------------+-----------------+
  5. | 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
  6. | 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
  7. +----------+-----------+--------------------+-----------------+
  8. 2 rows in set (0.00 sec)
  9. mysql>

从第4条开始的记录有两条,限制条数为3,所以这两条记录都可以被展示在结果集中。

使用默认的开始行

LIMIT后边也可以只有一个参数,那这个参数就代表着限制行数。也就是说我们可以不指定开始行,默认的开始行就是第0行,比如我们可以这么写:

  1. mysql> SELECT number, name, id_number, major FROM student_info LIMIT 3;
  2. +----------+-----------+--------------------+--------------------------+
  3. | number | name | id_number | major |
  4. +----------+-----------+--------------------+--------------------------+
  5. | 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
  6. | 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
  7. | 20180103 | 范统 | 17156319980116959X | 软件工程 |
  8. +----------+-----------+--------------------+--------------------------+
  9. 3 rows in set (0.00 sec)
  10. mysql>

查询结果就展示了从第0条开始的3条记录。

对查询结果排序

我们之前查询number列的时候得到的记录并不是有序的,这是为什么呢?MySQL其实默认会按照这些数据底层存储的顺序来给我们返回数据,但是这些数据可能会经过更新或者删除,如果我们不明确指定按照什么顺序来排序返回结果的话,那我们可以认为该结果中记录的顺序是不确定的。换句话说如果我们想让返回结果中的记录按照某种特定的规则排序,那我们必须显式的指定排序规则。

按照单个列的值进行排序

我们可以用下边的语法来指定返回结果的记录按照某一列的值进行排序:

  1. ORDER BY 列名 ASC|DESC

ASCDESC指的是排序方向。ASC是指按照指定列的值进行由小到大进行排序,也叫做升序DESC是指按照指定列的值进行由大到小进行排序,也叫做降序,中间的|表示这两种方式只能选一个。这回我们用student_score表测试一下:

  1. mysql> SELECT * FROM student_score ORDER BY score ASC;
  2. +----------+-----------------------------+-------+
  3. | number | subject | score |
  4. +----------+-----------------------------+-------+
  5. | 20180104 | 论萨达姆的战争准备 | 46 |
  6. | 20180104 | 母猪的产后护理 | 55 |
  7. | 20180103 | 母猪的产后护理 | 59 |
  8. | 20180103 | 论萨达姆的战争准备 | 61 |
  9. | 20180101 | 母猪的产后护理 | 78 |
  10. | 20180101 | 论萨达姆的战争准备 | 88 |
  11. | 20180102 | 论萨达姆的战争准备 | 98 |
  12. | 20180102 | 母猪的产后护理 | 100 |
  13. +----------+-----------------------------+-------+
  14. 8 rows in set (0.01 sec)
  15. mysql>

可以看到输出的记录就是按照成绩由小到大进行排序的。如果省略了 ORDER BY 语句中的排序方向,则默认按照从小到大的顺序进行排序,也就是说ORDER BY 列名ORDER BY 列名 ASC的语义是一样的,我们试一下:

  1. mysql> SELECT * FROM student_score ORDER BY score;
  2. +----------+-----------------------------+-------+
  3. | number | subject | score |
  4. +----------+-----------------------------+-------+
  5. | 20180104 | 论萨达姆的战争准备 | 46 |
  6. | 20180104 | 母猪的产后护理 | 55 |
  7. | 20180103 | 母猪的产后护理 | 59 |
  8. | 20180103 | 论萨达姆的战争准备 | 61 |
  9. | 20180101 | 母猪的产后护理 | 78 |
  10. | 20180101 | 论萨达姆的战争准备 | 88 |
  11. | 20180102 | 论萨达姆的战争准备 | 98 |
  12. | 20180102 | 母猪的产后护理 | 100 |
  13. +----------+-----------------------------+-------+
  14. 8 rows in set (0.01 sec)

再看一下从大到小排序的样子:

  1. mysql> SELECT * FROM student_score ORDER BY score DESC;
  2. +----------+-----------------------------+-------+
  3. | number | subject | score |
  4. +----------+-----------------------------+-------+
  5. | 20180102 | 母猪的产后护理 | 100 |
  6. | 20180102 | 论萨达姆的战争准备 | 98 |
  7. | 20180101 | 论萨达姆的战争准备 | 88 |
  8. | 20180101 | 母猪的产后护理 | 78 |
  9. | 20180103 | 论萨达姆的战争准备 | 61 |
  10. | 20180103 | 母猪的产后护理 | 59 |
  11. | 20180104 | 母猪的产后护理 | 55 |
  12. | 20180104 | 论萨达姆的战争准备 | 46 |
  13. +----------+-----------------------------+-------+
  14. 8 rows in set (0.00 sec)
  15. mysql>

按照多个列的值进行排序

我们也可以同时指定多个排序的列,多个排序列之间用逗号,隔开就好了,就是这样:

  1. ORDER BY 1 ASC|DESC, 2 ASC|DESC ...

比如我们想让对student_score的查询结果先按照subjuect排序,再按照score值从大到小的顺序进行排列,可以这么写:

  1. mysql> SELECT * FROM student_score ORDER BY subject, score DESC;
  2. +----------+-----------------------------+-------+
  3. | number | subject | score |
  4. +----------+-----------------------------+-------+
  5. | 20180102 | 母猪的产后护理 | 100 |
  6. | 20180101 | 母猪的产后护理 | 78 |
  7. | 20180103 | 母猪的产后护理 | 59 |
  8. | 20180104 | 母猪的产后护理 | 55 |
  9. | 20180102 | 论萨达姆的战争准备 | 98 |
  10. | 20180101 | 论萨达姆的战争准备 | 88 |
  11. | 20180103 | 论萨达姆的战争准备 | 61 |
  12. | 20180104 | 论萨达姆的战争准备 | 46 |
  13. +----------+-----------------------------+-------+
  14. 8 rows in set (0.00 sec)
  15. mysql>

再提醒一遍,如果不指定排序方向,则默认使用的是ASC,也就是从小到大的升序规则。

小贴士: 对于数字的排序还是很好理解的,但是字符串怎么排序呢?大写的A和小写的a哪个大哪个小?这个问题涉及到字符串使用的编码方式以及字符串排序规则,我们之后会详细的介绍它们,现在你只需要知道排序的语法就好了。

我们还可以让ORDER BY语句和LIMIT语句结合使用,不过 ORDER BY 语句必须放在 LIMIT 语句前边,比如这样:

  1. mysql> SELECT * FROM student_score ORDER BY score LIMIT 1;
  2. +----------+-----------------------------+-------+
  3. | number | subject | score |
  4. +----------+-----------------------------+-------+
  5. | 20180104 | 论萨达姆的战争准备 | 46 |
  6. +----------+-----------------------------+-------+
  7. 1 row in set (0.00 sec)
  8. mysql>

这样就能找出成绩最低的那条记录了。