上集中咱们唠叨了数据库的建立、选择和删除,表的建立、修改和删除以及简单的查询和插入命令。可是这只是搭建了一个空架子,其实对于MySQL
来讲,咱们平时使用频率最高的仍是查询功能,本集将详细聚焦各类让人眼花缭乱的查询方式,认真看,仔细看,滴点儿莎普爱思拿抹布擦擦眼继续看!本集的东西真的很是重要!mysql
话说本集的主题是查询数据,因此先得肯定一下查哪一个表吧,肯定了表以后表里头先得有数据吧,要不查个屁呀~ 因此咱们先搞定用什么表和为表中填入数据的工做。程序员
为简单起见,咱们就复用以前在数据库xiaohaizi
下边建立的学生信息表student_info
和学生成绩表student_score
,你可能有点忘了这两个表长啥样了,咱们先把两个表的结构回顾一下:sql
CREATE TABLE student_info (
number INT PRIMARY KEY,
name VARCHAR(5),
sex ENUM('男', '女'),
id_number CHAR(18),
department VARCHAR(30),
major VARCHAR(30),
enrollment_time DATE,
UNIQUE KEY (id_number)
);
复制代码
CREATE TABLE student_score (
number INT,
subject VARCHAR(30),
score TINYINT,
PRIMARY KEY (number, subject),
CONSTRAINT FOREIGN KEY(number) REFERENCES student_info(number)
);
复制代码
咱们给这两个表插入一些数据:数据库
mysql> INSERT INTO student_info(number, name, sex, id_number, department, major, enrollment_time) VALUES
-> (20180101, '杜子腾', '男', '158177199901044792', '计算机学院', '计算机科学与工程', '2018-09-01'),
-> (20180102, '杜琦燕', '女', '151008199801178529', '计算机学院', '计算机科学与工程', '2018-09-01'),
-> (20180103, '范统', '男', '17156319980116959X', '计算机学院', '软件工程', '2018-09-01'),
-> (20180104, '史珍香', '女', '141992199701078600', '计算机学院', '软件工程', '2018-09-01'),
-> (20180105, '范剑', '男', '181048199308156368', '航天学院', '飞行器设计', '2018-09-01'),
-> (20180106, '朱逸群', '男', '197995199501078445', '航天学院', '电子信息', '2018-09-01');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> INSERT INTO student_score (number, subject, score) VALUES
-> (20180101, '母猪的产后护理', 78),
-> (20180101, '论萨达姆的战争准备', 88),
-> (20180102, '母猪的产后护理', 100),
-> (20180102, '论萨达姆的战争准备', 98),
-> (20180103, '母猪的产后护理', 59),
-> (20180103, '论萨达姆的战争准备', 61),
-> (20180104, '母猪的产后护理', 55),
-> (20180104, '论萨达姆的战争准备', 46);
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql>
复制代码
如今这两个表中的数据就以下所示了:bash
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 |
number | subject | score |
---|---|---|
20180101 | 母猪的产后护理 | 78 |
20180101 | 论萨达姆的战争准备 | 88 |
20180102 | 母猪的产后护理 | 100 |
20180102 | 论萨达姆的战争准备 | 98 |
20180103 | 母猪的产后护理 | 59 |
20180103 | 论萨达姆的战争准备 | 61 |
20180104 | 母猪的产后护理 | 55 |
20180104 | 论萨达姆的战争准备 | 46 |
好了,表的填充工做也已经作完了~ 终于能够开始查询数据了!性能
查看某个表中的某一列的数据的通用格式是这样:学习
SELECT 列名 FROM 表名;
复制代码
好比查看student_info
表中的number
列的数据能够这么写:测试
mysql> SELECT number FROM student_info;
+----------+
| number |
+----------+
| 20180104 |
| 20180102 |
| 20180101 |
| 20180103 |
| 20180105 |
| 20180106 |
+----------+
6 rows in set (0.00 sec)
mysql>
复制代码
咱们把要查询的东西称为查询对象
,本例中的查询对象就是number
列,由于查询的结果也是由一条一条记录组成的,像记录的集合同样,因此有时候咱们会吧获得的查询结果称为结果集
。优化
小贴士: 你可能发现查询出的数据并非有序的,这个咱们稍后就会说到,稍安勿躁 ui
咱们也能够为结果集中的列从新定义一个别名
,命令格式以下:
SELECT 列名 [AS] 列的别名 FROM 表名;
复制代码
咱们看到AS
被加了个中括号,意味着无关紧要,没有AS
的话,列名和列的别名用空白字符隔开就行了。好比咱们想给number
列起个别名,下边这两种方式均可以使用:
方式一
SELECT number AS 学号 FROM student_info;
复制代码
方式二:
SELECT number 学号 FROM student_info;
复制代码
咱们执行一下:
mysql> SELECT number AS 学号 FROM student_info;
+----------+
| 学号 |
+----------+
| 20180104 |
| 20180102 |
| 20180101 |
| 20180103 |
| 20180105 |
| 20180106 |
+----------+
6 rows in set (0.00 sec)
mysql>
复制代码
看到黑框框里显示的列名就再也不是number
,而是咱们刚刚定义的别名学号
了。不过须要注意的是:列名只是做用在本次查询的显示结果中,而不会改变真实表中的列名,也就是说下一次查询中你对number
列取别的列名也能够,好比这样:
mysql> SELECT number xuehao FROM student_info;
+----------+
| xuehao |
+----------+
| 20180104 |
| 20180102 |
| 20180101 |
| 20180103 |
| 20180105 |
| 20180106 |
+----------+
6 rows in set (0.00 sec)
mysql>
复制代码
此次输出的列名就是另外一个别名xuehao
了。
若是想查询多个列的数据,能够在SELECT
后边写多个列名,用逗号,
分隔开就好:
SELECT 列名1, 列名2, ... 列名n FROM 表名;
复制代码
咱们把多个查询对象
组成的列表称为查询列表
,须要注意的是,查询列表中的列名能够按任意顺序摆放,结果集将按照咱们给出的列名顺序显示。好比咱们查询student_info
中的多个列:
mysql> SELECT number, name, id_number, major FROM student_info;
+----------+-----------+--------------------+--------------------------+
| number | name | id_number | major |
+----------+-----------+--------------------+--------------------------+
| 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
| 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
| 20180103 | 范统 | 17156319980116959X | 软件工程 |
| 20180104 | 史珍香 | 141992199701078600 | 软件工程 |
| 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
| 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
+----------+-----------+--------------------+--------------------------+
6 rows in set (0.00 sec)
mysql>
复制代码
本例中的查询列表就是number,name,id_number,major
,因此结果集中列的顺序就按找这个顺序来显示。固然,咱们也能够用别名来输出这些数据:
mysql> SELECT number AS 学号, name AS 姓名, id_number AS 身份证号, major AS 专业 FROM student_info;
+----------+-----------+--------------------+--------------------------+
| 学号 | 姓名 | 身份证号 | 专业 |
+----------+-----------+--------------------+--------------------------+
| 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
| 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
| 20180103 | 范统 | 17156319980116959X | 软件工程 |
| 20180104 | 史珍香 | 141992199701078600 | 软件工程 |
| 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
| 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
+----------+-----------+--------------------+--------------------------+
6 rows in set (0.00 sec)
mysql>
复制代码
若是你乐意,同一个查询对象能够在查询列表处重复出现(虽然这一般没什么卵用),好比这样:
mysql> SELECT number, number, number FROM student_info;
+----------+----------+----------+
| number | number | number |
+----------+----------+----------+
| 20180104 | 20180104 | 20180104 |
| 20180102 | 20180102 | 20180102 |
| 20180101 | 20180101 | 20180101 |
| 20180103 | 20180103 | 20180103 |
| 20180105 | 20180105 | 20180105 |
| 20180106 | 20180106 | 20180106 |
+----------+----------+----------+
6 rows in set (0.00 sec)
mysql>
复制代码
若是须要把记录中的全部列都查出来,MySQL
也提供一个省事儿的办法,咱们以前也介绍过,就是直接用星号*
来表示要查询的东西,就像这样:
SELECT * FROM 表名;
复制代码
这个命令咱们以前看过了,就很少唠叨了。不过须要注意的是,除非你确实须要表中的每一个列,不然通常最好别使用星号*
来查询全部列,虽然星号*
看起来很方便,不用明确列出所需的列,可是查询不须要的列一般会下降性能。
有的时候咱们查询某个列的数据时会有一些重复的结果,好比咱们查询一下student_info
表的学院信息:
mysql> SELECT department FROM student_info;
+-----------------+
| department |
+-----------------+
| 计算机学院 |
| 计算机学院 |
| 计算机学院 |
| 计算机学院 |
| 航天学院 |
| 航天学院 |
+-----------------+
6 rows in set (0.00 sec)
复制代码
由于表里有6条记录,因此给咱们返回了6条结果。可是其实好多都是重复的结果,若是咱们想去除重复结果的话,可使用DISTINCT
放在被查询的列前边,就是这样:
SELECT DISTINCT 列名 FROM 表名;
复制代码
咱们对学院信息作一下去重处理:
mysql> SELECT DISTINCT department FROM student_info;
+-----------------+
| department |
+-----------------+
| 计算机学院 |
| 航天学院 |
+-----------------+
2 rows in set (0.00 sec)
复制代码
看到结果只剩下不重复的信息了。
对于查询多列的状况,两条记录重复的意思是:两条记录的每个列中的值都相同。好比查询学院和专业信息:
mysql> SELECT department, major FROM student_info;
+-----------------+--------------------------+
| department | major |
+-----------------+--------------------------+
| 计算机学院 | 计算机科学与工程 |
| 计算机学院 | 计算机科学与工程 |
| 计算机学院 | 软件工程 |
| 计算机学院 | 软件工程 |
| 航天学院 | 飞行器设计 |
| 航天学院 | 电子信息 |
+-----------------+--------------------------+
6 rows in set (0.00 sec)
复制代码
查询结果中第一、2行记录中的department
和major
列都相同,因此这两行记录就是重复的,同理,第三、4行也是重复的。若是咱们想对多列查询的结果去重的话,能够直接把DISTINCT
放在被查询的列的最前边:
SELECT DISTINCT 列名1, 列名2, ... 列名n FROM 表名;
复制代码
好比这样:
mysql> SELECT DISTINCT department, major FROM student_info;
+-----------------+--------------------------+
| department | major |
+-----------------+--------------------------+
| 计算机学院 | 计算机科学与工程 |
| 计算机学院 | 软件工程 |
| 航天学院 | 飞行器设计 |
| 航天学院 | 电子信息 |
+-----------------+--------------------------+
4 rows in set (0.00 sec)
mysql>
复制代码
DISTINCT
不能作到一部分查询列去重,另外一部分不去重。由于查询结果是以行为单位展现的,若是你只对department
去重,那department
那一列只剩下4行数据,对major
列不去重,那major
列剩下了8行数据,那结果应该怎么展现呢?因此咱们规定DISTINCT
只能用来对所有列的值都相同的记录来进行去重。
有时候查询结果的条数会不少,都显示出来可能会撑爆屏幕~ 因此MySQL
给咱们提供了一种限制结果条数的方式,就是在查询语句的末尾使用这样的语法:
LIMIT 开始行, 限制条数;
复制代码
开始行
指的是咱们想从第几行数据开始查询,限制条数
是查询结果最多返回的记录条数。
小贴士 在生活中一般都是从1开始计数的,而在计算机中都是从0开始计数的,因此咱们平时所说的第1条记录在计算机中算是第0条。好比`student_info`表里的6条记录在计算机中依次表示为:第0条、第1条、第2条、第3条、第4条、第5条。
好比咱们查询一下student_info
表,从第0条记录开始,最多查询2条记录能够这么写:
mysql> SELECT number, name, id_number, major FROM student_info LIMIT 0, 2;
+----------+-----------+--------------------+--------------------------+
| number | name | id_number | major |
+----------+-----------+--------------------+--------------------------+
| 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
| 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
+----------+-----------+--------------------+--------------------------+
2 rows in set (0.00 sec)
mysql>
复制代码
若是指定的开始行
大于结果中的行数,那查询结果就是什么都没有:
mysql> SELECT number, name, id_number, major FROM student_info LIMIT 6, 2;
Empty set (0.00 sec)
mysql>
复制代码
若是查询的结果条数小于限制条数
,那就能够所有显式出来:
mysql> SELECT number, name, id_number, major FROM student_info LIMIT 4, 3;
+----------+-----------+--------------------+-----------------+
| number | name | id_number | major |
+----------+-----------+--------------------+-----------------+
| 20180105 | 范剑 | 181048199308156368 | 飞行器设计 |
| 20180106 | 朱逸群 | 197995199501078445 | 电子信息 |
+----------+-----------+--------------------+-----------------+
2 rows in set (0.00 sec)
mysql>
复制代码
从第4条开始的记录有两条,限制条数
为3,因此结果均可以显示出来。
LIMIT
后边也能够只有一个参数,那这个参数就表明着限制行数
。也就是说咱们能够不指定开始行
,默认的开始行就是第0行,好比咱们能够这么写:
mysql> SELECT number, name, id_number, major FROM student_info LIMIT 3;
+----------+-----------+--------------------+--------------------------+
| number | name | id_number | major |
+----------+-----------+--------------------+--------------------------+
| 20180101 | 杜子腾 | 158177199901044792 | 计算机科学与工程 |
| 20180102 | 杜琦燕 | 151008199801178529 | 计算机科学与工程 |
| 20180103 | 范统 | 17156319980116959X | 软件工程 |
+----------+-----------+--------------------+--------------------------+
3 rows in set (0.00 sec)
mysql>
复制代码
查询结果就展现了从第0条开始的3条记录。
咱们以前查询number
列的时候获得的记录并非有序的,这是为何呢?MySQL
其实默认会按照这些数据底层存储的顺序来给咱们返回数据,可是这些数据可能会通过更新或者删除,若是咱们不明确指定按照什么顺序来排序返回结果的话,那咱们能够认为该结果中记录的顺序是不肯定的。换句话说若是咱们想让返回结果中的记录按照某种特定的规则排序,那咱们必须显式的指定排序规则。
咱们能够用下边的语法来指定返回结果的记录按照某一列的值进行排序:
ORDER BY 列名 ASC|DESC
复制代码
ASC
和DESC
指的是排序方向。ASC
是指按照指定列的值进行由小到大进行排序,也叫作升序
,DESC
是指按照指定列的值进行由大到小进行排序,也叫作降序
,中间的|
表示这两种方式只能选一个。这回咱们用student_score
表测试一下:
mysql> SELECT * FROM student_score ORDER BY score ASC;
+----------+-----------------------------+-------+
| number | subject | score |
+----------+-----------------------------+-------+
| 20180104 | 论萨达姆的战争准备 | 46 |
| 20180104 | 母猪的产后护理 | 55 |
| 20180103 | 母猪的产后护理 | 59 |
| 20180103 | 论萨达姆的战争准备 | 61 |
| 20180101 | 母猪的产后护理 | 78 |
| 20180101 | 论萨达姆的战争准备 | 88 |
| 20180102 | 论萨达姆的战争准备 | 98 |
| 20180102 | 母猪的产后护理 | 100 |
+----------+-----------------------------+-------+
8 rows in set (0.01 sec)
mysql>
复制代码
能够看到输出的记录就是按照成绩由小到大进行排序的。若是省略了 ORDER BY 语句中的排序方向,则默认按照从小到大的顺序进行排序,也就是说ORDER BY 列名
和ORDER BY 列名 ASC
的语义是同样的,咱们试一下:
mysql> SELECT * FROM student_score ORDER BY score;
+----------+-----------------------------+-------+
| number | subject | score |
+----------+-----------------------------+-------+
| 20180104 | 论萨达姆的战争准备 | 46 |
| 20180104 | 母猪的产后护理 | 55 |
| 20180103 | 母猪的产后护理 | 59 |
| 20180103 | 论萨达姆的战争准备 | 61 |
| 20180101 | 母猪的产后护理 | 78 |
| 20180101 | 论萨达姆的战争准备 | 88 |
| 20180102 | 论萨达姆的战争准备 | 98 |
| 20180102 | 母猪的产后护理 | 100 |
+----------+-----------------------------+-------+
8 rows in set (0.01 sec)
复制代码
再看一下从大到小排序的样子:
mysql> SELECT * FROM student_score ORDER BY score DESC;
+----------+-----------------------------+-------+
| number | subject | score |
+----------+-----------------------------+-------+
| 20180102 | 母猪的产后护理 | 100 |
| 20180102 | 论萨达姆的战争准备 | 98 |
| 20180101 | 论萨达姆的战争准备 | 88 |
| 20180101 | 母猪的产后护理 | 78 |
| 20180103 | 论萨达姆的战争准备 | 61 |
| 20180103 | 母猪的产后护理 | 59 |
| 20180104 | 母猪的产后护理 | 55 |
| 20180104 | 论萨达姆的战争准备 | 46 |
+----------+-----------------------------+-------+
8 rows in set (0.00 sec)
mysql>
复制代码
咱们也能够同时指定多个排序的列,多个排序列之间用逗号,
隔开就行了,就是这样:
ORDER BY 列1 ASC|DESC, 列2 ASC|DESC ...
复制代码
好比咱们想让对student_score
的查询结果先按照subjuect
排序,再按照score
值从大到小的顺序进行排列,能够这么写:
mysql> SELECT * FROM student_score ORDER BY subject, score DESC;
+----------+-----------------------------+-------+
| number | subject | score |
+----------+-----------------------------+-------+
| 20180102 | 母猪的产后护理 | 100 |
| 20180101 | 母猪的产后护理 | 78 |
| 20180103 | 母猪的产后护理 | 59 |
| 20180104 | 母猪的产后护理 | 55 |
| 20180102 | 论萨达姆的战争准备 | 98 |
| 20180101 | 论萨达姆的战争准备 | 88 |
| 20180103 | 论萨达姆的战争准备 | 61 |
| 20180104 | 论萨达姆的战争准备 | 46 |
+----------+-----------------------------+-------+
8 rows in set (0.00 sec)
mysql>
复制代码
再提醒一遍,若是不指定排序方向,则默认使用的是ASC
,也就是从小到大的升序规则。
小贴士: 对于数字的排序仍是很好理解的,可是字符串怎么排序呢?大写的A和小写的a哪一个大哪一个小?这个问题涉及到字符串使用的编码方式以及字符串排序规则,咱们以后会详细的介绍它们,如今你只须要知道排序的语法就行了。
咱们还可让ORDER BY
语句和LIMIT
语句结合使用,不过 ORDER BY 语句必须放在 LIMIT 语句前边,好比这样:
mysql> SELECT * FROM student_score ORDER BY score LIMIT 1;
+----------+-----------------------------+-------+
| number | subject | score |
+----------+-----------------------------+-------+
| 20180104 | 论萨达姆的战争准备 | 46 |
+----------+-----------------------------+-------+
1 row in set (0.00 sec)
mysql>
复制代码
这样就能找出成绩最低的那条记录了。
咱们能够在SELECT后边指定要查询的列的列表,而后在FROM后边指定要查询的表,能够只查询单个列的值,也能够查询多个列的值,也可使用*简单的表明查询全部列的值。
若是咱们想去除重复结果的话,可使用DISTINCT放在被查询的列前边。须要注意的是,两条记录重复的意思是,因此使用DISTINCT在多个列上会把两条记录的每个列中的值都相同的重复行去掉,而不能作到不能作到一部分列去重,另外一部分不去重。
使用LIMIT语句限制查询结果的行数,LIMIT子句能够携带两个参数,其中开始行指的是咱们想从第几行数据开始查询,限制条数是查询结果最多返回的记录条数。参数开始行能够被省略,默认从第0行开始。
若是咱们想让返回结果中的记录按照某种特定的规则排序,那咱们必须显式的使用ORDER BY指定排序规则。其中,ASC指按照指定列的值的升序排序,DESC指按照指定列的值的降序排序。若是ORDER BY子句后有多个列的话,会先按照前边的列进行排序,若是前边的列的值相同,在相同的这些行中再按照后边的列进行排序。
本系列专栏都是MySQL入门知识,想看进阶知识能够到小册中查看:《MySQL是怎样运行的:从根儿上理解MySQL》的连接 。小册的内容主要是从小白的角度出发,用比较通俗的语言讲解关于MySQL进阶的一些核心概念,好比记录、索引、页面、表空间、查询优化、事务和锁等,总共的字数大约是三四十万字,配有上百幅原创插图。主要是想下降普通程序员学习MySQL进阶的难度,让学习曲线更平滑一点~