(查)基本查询
SELECT 字段名1,字段名2,… FROM 表名 [WHERE 条件表达式];
MySQL [mysql_chuid]> select * from students; # 查询students表中的所有信息
+----+-----------+------+
| id | name_list | sex |
+----+-----------+------+
| 1 | chd | man |
| 2 | chuid | man |
| 3 | anivd | man |
| 5 | chen | man |
+----+-----------+------+
4 rows in set (0.00 sec)
MySQL [mysql_chuid]> select name_list from students where id=2; # 查询id=2那一列name_list字段的信息
+-----------+
| name_list |
+-----------+
| chuid |
+-----------+
1 row in set (0.00 sec)
MySQL [mysql_chuid]> select sex from students where id=2; # 查询id=2那一列sex字段的信息
+------+
| sex |
+------+
| man |
+------+
1 row in set (0.00 sec)
(查)查询表的详细信息
SHOW CREATE TABLE命令会以SQL语句的形式来展示表信息。和DESCRIBE相比,SHOW CREATE TABLE展示的内容更加丰富,它可以查看表的存储引擎和字符编码;另外,你还可以通过\g或者\G参数来控制展示格式。
在SHOW CREATE TABLE语句的结尾处(分号前面)添加\g或者\G参数可以改变展示形式。
SHOW CREATE TABLE的语法格式:SHOW CREATE TABLE <表名>\G;
# 在MySQL表中查询表的详细信息
语法格式:show table status like ‘表名’;
show table status like ‘表名’\G;
MySQL [mysql_chuid]> show table status like 'students'\G; # 加 \G 可以格式化输出
*************************** 1. row ***************************
Name: students
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 5
Avg_row_length: 3276
Data_length: 16384
Max_data_length: 0
Index_length: 16384
Data_free: 0
Auto_increment: NULL
Create_time: 2021-02-05 09:44:39
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
MySQL [mysql_chuid]> show create table class_2\G;
*************************** 1. row ***************************
Table: class_2
Create Table: CREATE TABLE `class_2` (
`id` int(5) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`claID` int(10) DEFAULT NULL,
`grades` float DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_cla1_cla2` (`claID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
条件查询
条件 | 表达式举例1 | 说明 |
使用=判断相等 | height = 170 | 字符串需要用单引号括起来 |
使用>判断大于 | height > 170 | 字符串比较根据ASCII码,中文字符比较根据数据库设置 |
使用>=判断大于或相等 | height >= 170 |
|
使用<判断小于 | height < 170 |
|
使用<=判断小于或相等 | height <= 170 |
|
使用<>判断不相等 | height <> 170 |
|
使用LIKE判断相似 | Name LIKE’hd%’ | %表示任意字符,例如’hd%’将匹配’hd’,’chd’,’chuid’ |
在MySQL中,如果需要有条件的从数据表中查询数据,可以使用WHERE关键字来指定查询条件。
* 查询条件可以是:
1)带比较运算符和逻辑运算符的查询条件
2)带BETWEEN AND关键字的查询条件
3)带IS NULL关键字的查询条件
4)带IN关键字的查询条件
5)带LIKE关键字的查询条件
语法:SELECT * FROM <表名> WHERE <条件表达式>;
# 使用 SELECT * FROM <表名> 可以查询到一张表的所有记录;当你不需要所有记录时,可以根据条件选择性的获取指定条件的记录。
MySQL [mysql_chuid]> select * from students where height <= 170;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 2 | wang | woman | 105 | 165 |
| 7 | zhang | woman | 98 | 162 |
+----+-----------+-------+--------+--------+
2 rows in set (0.00 sec)
MySQL [mysql_chuid]> select * from students where sex='woman';
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 2 | wang | woman | 105 | 165 |
| 7 | zhang | woman | 98 | 162 |
+----+-----------+-------+--------+--------+
2 rows in set (0.02 sec)
MySQL [mysql_chuid]> select * from students where sex='woman' or height <= 170;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 2 | wang | woman | 105 | 165 |
| 7 | zhang | woman | 98 | 162 |
+----+-----------+-------+--------+--------+
2 rows in set (0.00 sec)
MySQL [mysql_chuid]> select * from students where sex='woman' and height=165;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 2 | wang | woman | 105 | 165 |
+----+-----------+-------+--------+--------+
1 row in set (0.00 sec)
MySQL [mysql_chuid]> select * from students where not id= 2;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 1 | chd | man | 130 | 171 |
| 5 | anivd | man | 130 | 171 |
| 6 | chen | man | 130 | 171 |
| 7 | zhang | woman | 98 | 162 |
| 8 | chuid | man | 130 | 171 |
+----+-----------+-------+--------+--------+
5 rows in set (0.03 sec)
MySQL [mysql_chuid]> select * from students where not id < 2 or id > 8;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 2 | wang | woman | 105 | 165 |
| 5 | anivd | man | 130 | 171 |
| 6 | chen | man | 130 | 171 |
| 7 | zhang | woman | 98 | 162 |
| 8 | chuid | man | 130 | 171 |
+----+-----------+-------+--------+--------+
5 rows in set (0.00 sec)
MySQL [mysql_chuid]> select * from students where (id < 2 or id > 8) and sex='man';
+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+------+--------+--------+
| 1 | chd | man | 130 | 171 |
+----+-----------+------+--------+--------+
1 row in set (0.00 sec)
(查)单一条件的查询
单一条件指的是在 WHERE 关键字后只有一个查询条件。
MySQL [mysql_chuid]> SELECT name_list,height FROM students WHERE height=171; # 查询students表中身高为171的人
+-----------+--------+
| name_list | height |
+-----------+--------+
| chd | 171 |
| anivd | 171 |
+-----------+--------+
2 rows in set (0.01 sec)
MySQL [mysql_chuid]> SELECT name_list,height FROM students WHERE height<170; # 查询students表中身高小于170的人
+-----------+--------+
| name_list | height |
+-----------+--------+
| wang | 165 |
| li | 169 |
| liu | 169 |
| luo | 162 |
| zhang | 162 |
+-----------+--------+
5 rows in set (0.01 sec)
(查)多条件的查询
在WHERE关键词后可以有多个查询条件,这样能够使查询结果更加精确。多个查询条件时用逻辑运算符AND(&&)、OR(||)或XOR隔开。
1)AND:记录满足所有查询条件时,才会被查询出来。
2)OR:记录满足任意一个查询条件时,才会被查询出来。
3)XOR:记录满足其中一个条件,并且不满足另一个条件时,才会被查询出来。
# 查询students表中weight大于100并且height小于170的人
MySQL [mysql_chuid]> SELECT name_list,height FROM students WHERE weight>100 AND height<170;
+-----------+--------+
| name_list | height |
+-----------+--------+
| wang | 165 |
| li | 169 |
| liu | 169 |
| luo | 162 |
+-----------+--------+
4 rows in set (0.03 sec)
MySQL [mysql_chuid]> select * from students_5;
+----+-------+------+--------+--------+
| id | name | age | weight | height |
+----+-------+------+--------+--------+
| 1 | chd | 27 | 129 | 171 |
| 2 | chuid | 25 | 129 | 170 |
| 3 | chen | 26 | 128 | 171 |
| 5 | zhang | 26 | 105 | 162 |
| 6 | wang | 27 | 103 | 159 |
| 7 | liu | 27 | 102 | 158 |
| 8 | guo | 28 | 98 | 156 |
+----+-------+------+--------+--------+
7 rows in set (0.00 sec)
# 查询students表中age大于等于26或者height小于170的人
MySQL [mysql_chuid]> SELECT name,age height FROM students_5 WHERE age>=26 OR height<170;
+-------+--------+
| name | height |
+-------+--------+
| chd | 27 |
| chen | 26 |
| zhang | 26 |
| wang | 27 |
| liu | 27 |
| guo | 28 |
+-------+--------+
6 rows in set (0.00 sec)
# 查询students表中age大于等于26并且height小于170的人和age小于等于26并且height大于170的人
MySQL [mysql_chuid]> SELECT name,age height FROM students_5 WHERE age>=26 XOR height<170;
+------+--------+
| name | height |
+------+--------+
| chd | 27 |
| chen | 26 |
+------+--------+
2 rows in set (0.00 sec)
模糊查询
LIKE关键字主要用于搜索匹配字段中的指定内容。
语法格式:[NOT] LIKE '字符串'
* 语法说明:
1)NOT:可选参数,字段中的内容与指定的字符串不匹配时满足条件。
2)字符串:指定用来匹配的字符串。“字符串”可以是一个很完整的字符串,也可以包含通配符。
3)LIKE关键字支持百分号“%”和下划线“_”通配符。
* 通配符是一种特殊语句,主要用来模糊查询。当不知道真正字符或者懒得输入完整名称时,可以使用通配符来代替一个或多个真正的字符。
(查)带有“%”通配符的查询
“%”是MySQL中最常用的通配符,它能代表任何长度的字符串,字符串的长度可以为0。例如,a%b表示以字母a开头,以字母b结尾的任意长度的字符串。该字符串可以代表ab、acb、accb、accrb等字符串。
# 查询students_5表中,所有以字母“c”开头的姓名 (匹配的字符串必须加单引号或双引号)
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name LIKE 'c%';
+-------+
| name |
+-------+
| chd |
| chen |
| chuid |
+-------+
3 rows in set (0.02 sec)
NOT LIKE表示字符串不匹配时满足条件。
# 查询students_5表中,所有不以字母“c”开头的姓名
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name NOT LIKE 'c%';
+-------+
| name |
+-------+
| guo |
| liu |
| wang |
| zhang |
+-------+
4 rows in set (0.01 sec)
# 查询students_5表中,所有包含字母“h”的姓名
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name LIKE '%h%';
+-------+
| name |
+-------+
| chd |
| chen |
| chuid |
| zhang |
+-------+
4 rows in set (0.00 sec)
(查)带有“_”通配符的查询
“_”只能代表单个字符,字符的长度不能为 0。例如,a_b可以代表 acb、adb、aub 等字符串。
# 查询students_5表中,所有以字母“d”结尾的姓名
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name LIKE '__d';
+------+
| name |
+------+
| chd |
+------+
1 row in set (0.00 sec)
LIKE区分大小写
默认情况下,LIKE关键字匹配字符的时候是不区分大小写的。如果需要区分大小写,可以加入BINARY关键字。
# 查询students_5表中,所有以字母“c”开头的姓名 (区分大小写和不区分大小写)
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name LIKE 'C%';
+-------+
| name |
+-------+
| chd |
| chen |
| chuid |
+-------+
3 rows in set (0.00 sec)
MySQL [mysql_chuid]> SELECT name FROM students_5 WHERE name LIKE BINARY 'C%';
Empty set (0.00 sec)
使用通配符的注意事项和技巧
* 使用通配符的一些注意事项:
1)注意大小写。MySQL默认是不区分大小写的。如果区分大小写,像“chd”这样的数据就不能被“C%”所匹配到。
2)注意尾部空格,尾部空格会干扰通配符的匹配。例如,“c% ”就不能匹配到“chd”。
3)注意NULL。“%”通配符可以到匹配任意字符,但是不能匹配NULL。也就是说“%”匹配不到students_5数据表中值为NULL的记录。
* 下面是一些使用通配符要记住的技巧:
1)不要过度使用通配符,如果其它操作符能达到相同的目的,应该使用其它操作符。因为 MySQL 对通配符的处理一般会比其他操作符花费更长的时间。
2)在确定使用通配符后,除非绝对有必要,否则不要把它们用在字符串的开始处。把通配符置于搜索模式的开始处,搜索起来是最慢的。
3)仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。
(查)范围查询
BETWEEN AND关键字,用来判断字段的数值是否在指定范围内。
BETWEEN AND需要两个参数,即范围的起始值和终止值。如果字段值在指定的范围内,则这些记录被返回。如果不在指定范围内,则不会被返回。
BETWEEN AND的基本语法格式:[NOT] BETWEEN 取值1 AND 取值2
* 语法说明:
1)NOT:可选参数,表示指定范围之外的值。如果字段值不满足指定范围内的值,则这些记录被返回。
2)取值1:表示范围的起始值。
3)取值2:表示范围的终止值。
* BETWEEN AND和NOT BETWEEN AND关键字在查询指定范围内的记录时很有用,例:查询年龄段、出生日期、工资水平等。
# 查询students_5表中,所有age在26到27岁之间的人 (BETWEEN AND能匹配指定范围内的所有值,包括起始值和终止值。)
MySQL [mysql_chuid]> SELECT name,age FROM students_5 WHERE age BETWEEN 26 AND 27;
+-------+------+
| name | age |
+-------+------+
| chd | 27 |
| chen | 26 |
| zhang | 26 |
| wang | 27 |
| liu | 27 |
+-------+------+
5 rows in set (0.00 sec)
# 查询students_5表中,所有age不在26到27岁之间的人
MySQL [mysql_chuid]> SELECT name,age FROM students_5 WHERE age NOT BETWEEN 26 AND 27;
+-------+------+
| name | age |
+-------+------+
| chuid | 25 |
| guo | 28 |
+-------+------+
2 rows in set (0.01 sec)
(查)空值查询 *
IS NULL关键字,用来判断字段的值是否为空值(NULL)。空值不同于 0,也不同于空字符串。
如果字段的值是空值,则满足查询条件,该记录将被查询出来。如果字段的值不是空值,则不满足查询条件。
使用IS NULL的基本语法格式:IS [NOT] NULL
其中,“NOT”是可选参数,表示字段值不是空值时满足条件
MySQL [mysql_chuid]> alter table students_5 add birthday char(10); # 新增birthday列,默认为NULL
Query OK, 0 rows affected (0.16 sec)
Records: 0 Duplicates: 0 Warnings: 0
MySQL [mysql_chuid]> update students_5 set birthday='10-16' where id=1; # 在birthday列id=1行插入“10-16”
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MySQL [mysql_chuid]> select * from students_5;
+----+-------+------+--------+--------+----------+----------+
| id | name | age | weight | height | birthday | address |
+----+-------+------+--------+--------+----------+----------+
| 1 | chd | 27 | 129 | 170 | 10-16 | hubei |
| 2 | chuid | 25 | 129 | 170 | 10-8 | jiayu |
| 3 | chen | 26 | 128 | 171 | 5-3 | shenzhen |
| 5 | zhang | 26 | 105 | 162 | 2-14 | shenzhen |
| 6 | wang | 27 | 103 | 159 | 6-5 | NULL |
| 7 | liu | 27 | 102 | 158 | 8-6 | NULL |
| 8 | guo | 28 | 98 | 156 | 11-30 | hunan |
+----+-------+------+--------+--------+----------+----------+
7 rows in set (0.00 sec)
# 使用IS NULL关键字,查询students_5表中字段是NULL的记录
MySQL [mysql_chuid]> SELECT name,address FROM students_5 where address IS NULL;
+------+---------+
| name | address |
+------+---------+
| wang | NULL |
| liu | NULL |
+------+---------+
2 rows in set (0.00 sec)
# 使用IS NOT NULL关键字,查询students_5表中字段不是NULL的记录
MySQL [mysql_chuid]> SELECT name,address FROM students_5 where address IS NOT NULL;
+-------+----------+
| name | address |
+-------+----------+
| chd | hubei |
| chuid | jiayu |
| chen | shenzhen |
| zhang | shenzhen |
| guo | hunan |
+-------+----------+
5 rows in set (0.00 sec)
(查)分组查询
GROUP BY关键字可以根据一个或多个字段对查询结果进行分组。
语法格式:GROUP BY <字段名>
其中,“字段名”表示需要分组的字段名称,多个字段时用逗号隔开。
MySQL [mysql_chuid]> select * from students;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 1 | chd | man | 130 | 171 |
| 2 | wang | woman | 105 | 165 |
| 3 | li | man | 132 | 169 |
| 4 | liu | woman | 132 | 169 |
| 5 | anivd | man | 130 | 171 |
| 6 | luo | woman | 118 | 162 |
| 7 | zhang | woman | 98 | 162 |
| 8 | chen | man | 130 | 170 |
+----+-----------+-------+--------+--------+
8 rows in set (0.00 sec)
# 根据students表中的sex字段进行分组查询,结果显示两条记录(sex字段值分别为“man”和“woman”)
MySQL [mysql_chuid]> select name_list,sex FROM students GROUP BY sex;
+-----------+-------+
| name_list | sex |
+-----------+-------+
| chd | man |
| wang | woman |
+-----------+-------+
2 rows in set (0.00 sec)
GROUP BY与GROUP_CONCAT()
GROUP BY关键字可以和GROUP_CONCAT()函数一起使用。GROUP_CONCAT()函数会把每个分组的字段值都显示出来。
# 根据students表中的sex字段进行分组查询,使用GROUP_CONCAT()函数将每个分组的name字段的值都显示出来
# sex字段值为“woman”的是一组,值为“man”的是一组
MySQL [mysql_chuid]> SELECT sex,GROUP_CONCAT(name_list) FROM students GROUP BY sex;
+-------+-------------------------+
| sex | GROUP_CONCAT(name_list) |
+-------+-------------------------+
| man | chd,li,anivd,chen |
| woman | wang,liu,luo,zhang |
+-------+-------------------------+
2 rows in set (0.00 sec)
# 根据students_5表中的age和name字段进行分组查询
# 先按照age字段进行分组,当age字段值相等时,再把age字段值相等的记录按照name字段进行分组
MySQL [mysql_chuid]> SELECT age,name,GROUP_CONCAT(height) FROM students_5 GROUP BY age,name;
+------+-------+----------------------+
| age | name | GROUP_CONCAT(height) |
+------+-------+----------------------+
| 25 | chuid | 170 |
| 26 | chen | 171 |
| 26 | zhang | 162 |
| 27 | chd | 170 |
| 27 | liu | 158 |
| 27 | wang | 159 |
| 28 | guo | 156 |
+------+-------+----------------------+
7 rows in set (0.00 sec)
* 多个字段分组查询时,会先按照第一个字段进行分组。如果第一个字段中有相同的值,MySQL才会按照第二个字段进行分组。如果第一个字段中的数据都是唯一的,那么MySQL将不再对第二个字段进行分组。
GROUP BY与聚合函数
在数据统计时,GROUP BY关键字经常和聚合函数一起使用。
聚合函数包括COUNT(),SUM(),AVG(),MAX()和MIN()。其中,COUNT()用来统计记录的条数;SUM()用来计算字段值的总和;AVG()用来计算字段值的平均值;MAX()用来查询字段的最大值;MIN()用来查询字段的最小值。
# 根据students表中的sex字段进行分组查询,使用COUNT()函数计算每一组的记录数。
MySQL [mysql_chuid]> SELECT sex, COUNT(sex) FROM students GROUP BY sex;
+-------+------------+
| sex | COUNT(sex) |
+-------+------------+
| man | 4 |
| woman | 4 |
+-------+------------+
2 rows in set (0.00 sec)
GROUP BY与WITH ROLLUP
WITH POLLUP关键字用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,即统计记录数量。
# 根据students表中的age字段进行分组查询,并使用WITH ROLLUP显示记录的总和
# GROUP_CONCAT(name)显示了每个分组的name字段值。同时最后一条记录的GROUP_CONCAT(name)字段的值刚好是上面分组name字段值的总和。
MySQL [mysql_chuid]> SELECT age,GROUP_CONCAT(name) FROM students_5 GROUP BY age WITH ROLLUP;
+------+-----------------------------------+
| age | GROUP_CONCAT(name) |
+------+-----------------------------------+
| 25 | chuid |
| 26 | chen,zhang |
| 27 | chd,wang,liu |
| 28 | guo |
| NULL | chuid,chen,zhang,chd,wang,liu,guo |
+------+-----------------------------------+
5 rows in set (0.06 sec)
(查)过滤分组
使用HAVING关键字对分组后的数据进行过滤。
语法格式:HAVING <查询条件>
HAVING关键字和WHERE关键字都可以用来过滤数据,且HAVING支持WHERE关键字中所有的操作符和语法。
* WHERE和HAVING关键字也存在以下几点差异:
1)一般情况下,WHERE用于过滤数据行,而HAVING用于过滤分组。
2)WHERE查询条件中不可以使用聚合函数,而HAVING查询条件中可以使用聚合函数。
3)WHERE在数据分组前进行过滤,而HAVING在数据分组后进行过滤。
4)WHERE针对数据库文件进行过滤,而HAVING针对查询结果进行过滤。也就是说,WHERE根据数据表中的字段直接进行过滤,而HAVING是根据前面已经查询出的字段进行过滤。
5)WHERE查询条件中不可以使用字段别名,而HAVING查询条件中可以使用字段别名。
# 使用HAVING和WHERE关键字查询出students表中身高大于等于165的学生姓名,性别和身高。
MySQL [mysql_chuid]> SELECT name_list,sex,height FROM students HAVING height>=165;
+-----------+-------+--------+
| name_list | sex | height |
+-----------+-------+--------+
| chd | man | 171 |
| wang | woman | 165 |
| li | man | 169 |
| liu | woman | 169 |
| anivd | man | 171 |
| chen | man | 170 |
+-----------+-------+--------+
6 rows in set (0.00 sec)
MySQL [mysql_chuid]> SELECT name_list,sex,height FROM students WHERE height>=165;
+-----------+-------+--------+
| name_list | sex | height |
+-----------+-------+--------+
| chd | man | 171 |
| wang | woman | 165 |
| li | man | 169 |
| liu | woman | 169 |
| anivd | man | 171 |
| chen | man | 170 |
+-----------+-------+--------+
6 rows in set (0.00 sec)
# 使用HAVING和WHERE关键字分别查询出students表中身高大于等于165的学生姓名和性别
MySQL [mysql_chuid]> SELECT name_list,sex FROM students WHERE height>=165;
+-----------+-------+
| name_list | sex |
+-----------+-------+
| chd | man |
| wang | woman |
| li | man |
| liu | woman |
| anivd | man |
| chen | man |
+-----------+-------+
6 rows in set (0.00 sec)
# 如果SELECT关键字后没有查询出HAVING查询条件中使用的height字段,MySQL会提示错误信息:“having子句”中的列“height”未知”。
MySQL [mysql_chuid]> SELECT name_list,sex FROM students HAVING height>=165;
ERROR 1054 (42S22): Unknown column 'height' in 'having clause'
# 根据height字段对students表中的数据进行分组,并使用HAVING和WHERE关键字分别查询出分组后平均身高小于170的学生姓名、性别和身高。
MySQL [mysql_chuid]> SELECT GROUP_CONCAT(name_list),sex,height FROM students GROUP BY height HAVING AVG(height)<170;
+-------------------------+-------+--------+
| GROUP_CONCAT(name_list) | sex | height |
+-------------------------+-------+--------+
| luo,zhang | woman | 162 |
| wang | woman | 165 |
| li,liu | man | 169 |
+-------------------------+-------+--------+
3 rows in set (0.00 sec)
# 在WHERE查询条件中使用聚合函数,MySQL会提示错误信息:无效使用组函数。
MySQL [mysql_chuid]> SELECT GROUP_CONCAT(name_list),sex,height FROM students WHERE AVG(height)<170 GROUP BY height;
ERROR 1111 (HY000): Invalid use of group function
(查)投影查询
# 投影查询的定义:如果我们只希望返回某些列的数据,而不是所有列的数据,我们可以用SELECT 列1,列2,列3...,让结果集仅包含指定列。
MySQL [mysql_chuid]> select id,name_list,sex from students;
+----+-----------+-------+
| id | name_list | sex |
+----+-----------+-------+
| 1 | chd | man |
| 2 | wang | woman |
| 5 | anivd | man |
| 6 | chen | man |
| 7 | zhang | woman |
| 8 | chuid | man |
+----+-----------+-------+
6 rows in set (0.00 sec)
# 使用投影查询时还可以给每一列起个别名,这样结果集的列名就可以与原表的列名不同
# 语法:SELECT 列1 别名1,列2 别名2,列3 别名3 FROM ...
MySQL [mysql_chuid]> SELECT id,name_list name,sex FROM students; # SELECT语句将列名name_list 重命名为name,而id和sex列名保持不变
+----+-------+-------+
| id | name | sex |
+----+-------+-------+
| 1 | chd | man |
| 2 | wang | woman |
| 5 | anivd | man |
| 6 | chen | man |
| 7 | zhang | woman |
| 8 | chuid | man |
+----+-------+-------+
6 rows in set (0.00 sec)
MySQL [mysql_chuid]> SELECT id,name_list name,height FROM students WHERE sex='woman';
+----+-------+--------+
| id | name | height |
+----+-------+--------+
| 2 | wang | 165 |
| 7 | zhang | 162 |
+----+-------+--------+
2 rows in set (0.00 sec)
(查)排序
# 使用SELECT查询时,查询结果集通常是按照ID(主键)排序的,如果我们要根据其他条件排序可以加上ORDER BY子句。
MySQL [mysql_chuid]> SELECT id,name_list,sex,height FROM students ORDER BY height; # 按height由低到高
+----+-----------+-------+--------+
| id | name_list | sex | height |
+----+-----------+-------+--------+
| 7 | zhang | woman | 162 |
| 2 | wang | woman | 165 |
| 1 | chd | man | 171 |
| 5 | anivd | man | 171 |
| 6 | chen | man | 171 |
| 8 | chuid | man | 171 |
+----+-----------+-------+--------+
6 rows in set (0.01 sec)
# 默认的排序规则是ASC表示“升序”,(ASC可以省略); DESC 表示“倒序”
MySQL [mysql_chuid]> SELECT id,name_list,sex,height FROM students ORDER BY height DESC; # 按height由高到低
+----+-----------+-------+--------+
| id | name_list | sex | height |
+----+-----------+-------+--------+
| 1 | chd | man | 171 |
| 5 | anivd | man | 171 |
| 6 | chen | man | 171 |
| 8 | chuid | man | 171 |
| 2 | wang | woman | 165 |
| 7 | zhang | woman | 162 |
+----+-----------+-------+--------+
6 rows in set (0.00 sec)
# 如果height有相同的数据要进一步排序,可以继续添加列名。
# 先按height列升序排序,如果有相同的,再按weight列排序
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students ORDER BY height,weight;
+----+-----------+-------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+-------+--------+--------+
| 7 | zhang | woman | 162 | 98 |
| 2 | wang | woman | 165 | 105 |
| 1 | chd | man | 171 | 130 |
| 5 | anivd | man | 171 | 130 |
| 6 | chen | man | 171 | 130 |
| 8 | chuid | man | 171 | 130 |
+----+-----------+-------+--------+--------+
6 rows in set (0.00 sec)
MySQL [mysql_chuid]> replace into students (id,name_list,sex,height,weight)values(8,'chen','man',170,130); # 替换原数据
Query OK, 3 rows affected (0.10 sec)
MySQL [mysql_chuid]> replace into students (id,name_list,sex,height,weight)values(8,'chuid','man',170,128); # 替换原数据
Query OK, 2 rows affected (0.03 sec)
MySQL [mysql_chuid]> select * from students; # 查询数据表students的所有数据信息
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 1 | chd | man | 130 | 171 |
| 2 | wang | woman | 105 | 165 |
| 5 | anivd | man | 130 | 171 |
| 7 | zhang | woman | 98 | 162 |
| 8 | chen | man | 130 | 170 |
+----+-----------+-------+--------+--------+
5 rows in set (0.00 sec)
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students WHERE weight=130 ORDER BY height DESC;
+----+-----------+------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+------+--------+--------+
| 1 | chd | man | 171 | 130 |
| 5 | anivd | man | 171 | 130 |
| 8 | chen | man | 170 | 130 |
+----+-----------+------+--------+--------+
3 rows in set (0.00 sec)
(查)分页查询
# 分页实际上是从结果集中截取出第M – N条记录。这个查询可以通过LIMIT<M> OFFDET <N>子句实现
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students ORDER BY height; # 按height排序
+----+-----------+-------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+-------+--------+--------+
| 7 | zhang | woman | 162 | 98 |
| 2 | wang | woman | 165 | 105 |
| 8 | chen | man | 170 | 130 |
| 1 | chd | man | 171 | 130 |
| 5 | anivd | man | 171 | 130 |
+----+-----------+-------+--------+--------+
5 rows in set (0.00 sec)
# LIMIT 3 OFFSET 0表示对结果集从0号记录开始,最多取3条。(SQL记录集的索引从0开始)
# LIMIT 3 表示的意思是“最多3条记录”
# LIMIT总是设定为pageSize;
# OFFSET计算公式为pageSize * (pageIndex - 1)
# OFFSET是可选的,如果只写LIMIT 5,那么相当于LIMIT 5 OFFSET 0
# 使用LIMIT <M> OFFSET <N>分页时,随着N越来越大,查询效率也会越来越低
# 使用LIMIT <M> OFFSET <N>可以对结果集进行分页,每次查询返回结果集的一部分
# 页查询需要先确定每页的数量和当前页数,然后确定LIMIT和OFFSET的值
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students ORDER BY height DESC LIMIT 3 OFFSET 0;
+----+-----------+------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+------+--------+--------+
| 1 | chd | man | 171 | 130 |
| 5 | anivd | man | 171 | 130 |
| 8 | chen | man | 170 | 130 |
+----+-----------+------+--------+--------+
3 rows in set (0.00 sec)
# 如果需要“跳过”头3条记录,也就是对结果集从3号记录开始查询,把OFFSET设定为3
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students ORDER BY height LIMIT 3 OFFSET 3;
+----+-----------+------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+------+--------+--------+
| 1 | chd | man | 171 | 130 |
| 5 | anivd | man | 171 | 130 |
+----+-----------+------+--------+--------+
2 rows in set (0.00 sec)
MySQL [mysql_chuid]> SELECT id,name_list,sex,height,weight FROM students ORDER BY height LIMIT 3 OFFSET 4;
+----+-----------+------+--------+--------+
| id | name_list | sex | height | weight |
+----+-----------+------+--------+--------+
| 5 | anivd | man | 171 | 130 |
+----+-----------+------+--------+--------+
1 row in set (0.00 sec)
(查)聚合查询
函数 | 说明 |
COUNT | 查询所有列的行数 |
SUM | 计算某一列的合计值,该列必须为数值类型 |
AVG | 计算某一列的平均数,该列必须为数值类型 |
MAX | 计算某一列的最大值 |
MIN | 计算某一列的最小值 |
# 统计一张表的数据量,查询数据表一共有多少条记录。对于统计总数、平均数这类计算,SQL提供了专门的聚合函数
# COUNT()表示查询所有列的行数,聚合的计算结果是一个数字,查询显示结果是一行一列的二维表,并且别名是COUNT()
MySQL [mysql_chuid]> SELECT COUNT(*) FROM students;
+----------+
| COUNT(*) |
+----------+
| 5 |
+----------+
1 row in set (0.09 sec)
MySQL [mysql_chuid]> SELECT COUNT(*) name_list FROM students WHERE sex='woman';
+-----------+
| name_list |
+-----------+
| 2 |
+-----------+
1 row in set (0.00 sec)
(查)多表查询
查询多张表的语法是:SELECT * FROM <表1> <表2>
# SELECT查询不但可以从一张表查询数据,还可以从多张表同时查询数据。
MySQL [mysql_chuid]> show tables;
+-----------------------+
| Tables_in_mysql_chuid |
+-----------------------+
| students |
| students_1 |
| students_2 |
+-----------------------+
3 rows in set (0.12 sec)
MySQL [mysql_chuid]> select * from students, students_1;
+----+-----------+-------+--------+--------+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height | id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+----+-----------+-------+--------+--------+
| 1 | chd | man | 130 | 171 | 7 | zhang | woman | 98 | 162 |
| 2 | wang | woman | 105 | 165 | 7 | zhang | woman | 98 | 162 |
| 5 | anivd | man | 130 | 171 | 7 | zhang | woman | 98 | 162 |
| 7 | zhang | woman | 98 | 162 | 7 | zhang | woman | 98 | 162 |
| 8 | chen | man | 130 | 170 | 7 | zhang | woman | 98 | 162 |
+----+-----------+-------+--------+--------+----+-----------+-------+--------+--------+
5 rows in set (0.07 sec)
(查)连接查询
连接查询是另一种类型的多表查询。连接查询对多个表进行JOIN运算,简单的说就是先确实一个主表作为结果集,然后把其他表的行有选择性的连接在主表结果集上。
* MySQL数据库支持如下连接查询:
* CROSS JOIN(交叉连接)
* INNER JOIN(内连接)
* OUTER JOIN(外连接)
* 其它
每个连接都只发生在两个表之间,即使FROM子句中包含多个表也是如此。每次连接操作也只进行逻辑查询语句的前三步,每次产生一个虚拟表,这个虚拟表再依次与FROM子句的下一个表进行连接,直到FROM子句中的表都被处理完为止。
MySQL [mysql_chuid]> insert into students_2(id,name_list,sex,weight,height) values (2,'chd','man',128,171);
Query OK, 1 row affected (0.01 sec)
MySQL [mysql_chuid]> insert into students_2(id,name_list,sex,weight,height) values (3,'chuid','man',130,172);
Query OK, 1 row affected (0.01 sec)
MySQL [mysql_chuid]> select * from students_2;
+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+------+--------+--------+
| 1 | chd | man | 130 | 171 |
| 2 | chd | man | 128 | 171 |
| 3 | chuid | man | 130 | 172 |
+----+-----------+------+--------+--------+
3 rows in set (0.00 sec)
MySQL [mysql_chuid]> update students_2 set name_list='chen' where id=1; # 将id=1的name_list改为chen
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MySQL [mysql_chuid]> select * from students_2;
+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+------+--------+--------+
| 1 | chen | man | 130 | 171 |
| 2 | chd | man | 128 | 171 |
| 3 | chuid | man | 130 | 172 |
+----+-----------+------+--------+--------+
3 rows in set (0.00 sec)
交叉查询(CROSS JOIN)
在关系型数据库中,表与表之间是有联系的,所以在实际应用中,经常使用多表查询。多表查询就是同时查询两个或两个以上的表。
交叉连接的语法格式:
SELECT <字段名> FROM <表1>, <表2> [WHERE子句]
SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句] # 官方标准写法
* 语法说明:
1)字段名:需要查询的字段名称。
2)<表1><表2>:需要交叉连接的表名。
3)WHERE 子句:用来设置交叉连接的查询条件。
MySQL [mysql_chuid]> select * from students_2; # 查询表students_2中的数据
+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+------+--------+--------+
| 1 | chd | man | 130 | 171 |
+----+-----------+------+--------+--------+
1 row in set (0.00 sec)
MySQL [mysql_chuid]> select * from students_3; # 查询表students_3中的数据
+----+-------+------+
| id | name | sex |
+----+-------+------+
| 1 | chuid | 26 |
+----+-------+------+
1 row in set (0.00 sec)
MySQL [mysql_chuid]> SELECT * FROM students_2 CROSS JOIN students_3; # 使用CROSS JOIN查询出两张表中的笛卡尔积
+----+-----------+------+--------+--------+----+-------+------+
| id | name_list | sex | weight | height | id | name | sex |
+----+-----------+------+--------+--------+----+-------+------+
| 1 | chd | man | 130 | 171 | 1 | chuid | 26 |
+----+-----------+------+--------+--------+----+-------+------+
1 row in set (0.01 sec)
* 表的数量较多时,交叉连接会非常非常慢。一般情况下不建议使用交叉连接。
* 多表查询一般使用内连接和外连接,它们的效率要高于交叉连接。
交叉连接对两个表执行FROM语句(笛卡尔积)操作,返回两个表中所有列的组合。如果左表有m行数据,右表有n行数据,执行CROSS JOIN将返回m*n行数据。CROSS JOIN只执行SQL逻辑查询语句执行的前三步中的第一步。
MySQL [mysql_chuid]> select * from students_1 cross join students_2;
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height | id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | 1 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | 1 | chen | man | 130 | 171 |
| 3 | chen | woman | 98 | 162 | 1 | chen | man | 130 | 171 |
| 1 | zhang | man | 128 | 172 | 2 | chd | man | 128 | 171 |
| 2 | wang | woman | 98 | 165 | 2 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | 2 | chd | man | 128 | 171 |
| 1 | zhang | man | 128 | 172 | 3 | chuid | man | 130 | 172 |
| 2 | wang | woman | 98 | 165 | 3 | chuid | man | 130 | 172 |
| 3 | chen | woman | 98 | 162 | 3 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
9 rows in set (0.13 sec)
内连接(INNER JOIN)
内连接(INNER JOIN)主要通过设置连接条件的方式,来移除查询结果中某些数据行的交叉连接。简单来说,就是利用条件表达式来消除交叉连接的某些数据行。
内连接使用INNER JOIN关键字连接两张表,并使用ON子句来设置连接条件。如果没有连接条件,INNER JOIN和CROSS JOIN在语法上是等同的,两者可以互换。
多个表内连接时,在FROM后连续使用INNER JOIN或JOIN即可。
内连接的语法格式:SELECT <字段名> FROM <表1> INNER JOIN <表2> [ON子句]
* 语法说明:
1)字段名:需要查询的字段名称。
2)<表1><表2>:需要内连接的表名。
3)INNER JOIN :内连接中可以省略INNER关键字,只用关键字JOIN。
4)ON子句:用来设置内连接的连接条件。
INNER JOIN可以根据一些过滤条件来匹配表之间的数据。在SQL逻辑查询语句执行的前三步中,INNER JOIN会执行第一步和第二步,不添加外部行。
MySQL [mysql_chuid]> select * from students_1 inner join students_2 on students_1.name_list=students_2.name_list;
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height | id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| 3 | chen | woman | 98 | 162 | 1 | chen | man | 130 | 171 |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
1 row in set (0.07 sec)
MySQL [mysql_chuid]> select * from students_1 inner join students_2 on students_1.id=students_2.id;
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| id | name_list | sex | weight | height | id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | 1 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | 2 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | 3 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+----+-----------+------+--------+--------+
3 rows in set (0.00 sec)
对于INNER JOIN来说,如果没有使用ON条件的过滤,INNER JOIN和CROSS JOIN的效果是一样的。当在ON中设置的过滤条件列具有相同的名称,我们可以使用USING关键字来简写ON的过滤条件,这样可以简化SQL语句
MySQL [mysql_chuid]> select * from students_1 inner join students_2 using(id);
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| id | name_list | sex | weight | height | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
3 rows in set (0.00 sec)
外连接(OUTER JOIN)
外连接可以分为左外连接和右外连接。
左外连接又称为左连接,使用LEFT OUTER JOIN关键字连接两个表,并使用ON子句来设置连接条件。
左连接的语法格式:SELECT <字段名> FROM <表1> LEFT OUTER JOIN <表2> <ON子句>
* 语法说明:
1)字段名:需要查询的字段名称。
2)<表1><表2>:需要左连接的表名。
3)LEFT OUTER JOIN:左连接中可以省略OUTER关键字,只使用关键字LEFT JOIN。
4)ON子句:用来设置左连接的连接条件,不能省略。
上述语法中,“表1”为基表,“表2”为参考表。左连接查询时,可以查询出“表1”中的所有记录和“表2”中匹配连接条件的记录。如果“表1”的某行在“表2”中没有匹配行,那么在返回结果中,“表2”的字段值均为空值(NULL)。
*******************************************************************************************************************************************
右外连接又称为右连接,右连接是左连接的反向连接。使用RIGHT OUTER JOIN关键字连接两个表,并使用ON子句来设置连接条件。
右连接的语法格式:SELECT <字段名> FROM <表1> RIGHT OUTER JOIN <表2> <ON子句>
* 语法说明:
1)字段名:需要查询的字段名称。
2)<表1><表2>:需要右连接的表名。
3)RIGHT OUTER JOIN:右连接中可以省略OUTER关键字,只使用关键字RIGHT JOIN。
4)ON子句:用来设置右连接的连接条件,不能省略。
与左连接相反,右连接以“表2”为基表,“表1”为参考表。右连接查询时,可以查询出“表2”中的所有记录和“表1”中匹配连接条件的记录。如果“表2”的某行在“表1”中没有匹配行,那么在返回结果中,“表1”的字段值均为空值(NULL)。
* 多个表左/右连接时,在 ON 子句后连续使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可。
* 使用外连接查询时,一定要分清需要查询的结果,是需要显示左表的全部记录还是右表的全部记录,然后选择相应的左连接和右连接。
通过OUTER JOIN可以按照一些过滤条件累匹配表之间的数据。OUTER JOIN的结果集等于INNER JOIN的结果集加上外部行(在使用OUTER JOIN时,SQL逻辑查询语句执行的前三步都会会执行一遍)
MySQL [mysql_chuid]> select * from students_1 left outer join students_2 on students_1.id=students_2.id;
+----+-----------+-------+--------+--------+------+-----------+------+--------+--------+
| id | name_list | sex | weight | height | id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+------+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | 1 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | 2 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | 3 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+------+-----------+------+--------+--------+
3 rows in set (0.15 sec)
MySQL数据库支持LEFT OUTER JOIN和RIGHT OUTER JOIN,与INNER关键字一样,我们可以省略OUTER关键字。对于OUTER JOIN,同样也可以使用USING来简化ON子句。
MySQL [mysql_chuid]> select * from students_1 left join students_2 using(id);
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| id | name_list | sex | weight | height | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
3 rows in set (0.00 sec)
与INNER JOIN还有一点区别,对于OUTER JOIN,必须制定ON或using子句,否则MySQL数据库会报错。
自然连接(NATURAL JOIN)
NATURAL JOIN等同于INNER(OUTER)JOIN与USING的组合,它隐含的作用是将两个表中具有相同名称的列进行匹配,同样的NATURAL LEFT(RIGHT)JOIN等同于LEFT(RIGHT)JOIN与USING的组合。
MySQL [mysql_chuid]> select * from students_1 left join students_2 using(id);
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| id | name_list | sex | weight | height | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
| 1 | zhang | man | 128 | 172 | chen | man | 130 | 171 |
| 2 | wang | woman | 98 | 165 | chd | man | 128 | 171 |
| 3 | chen | woman | 98 | 162 | chuid | man | 130 | 172 |
+----+-----------+-------+--------+--------+-----------+------+--------+--------+
3 rows in set (0.00 sec)
MySQL [mysql_chuid]> select * from students_1 natural left join students_2;
+----+-----------+-------+--------+--------+
| id | name_list | sex | weight | height |
+----+-----------+-------+--------+--------+
| 1 | zhang | man | 128 | 172 |
| 2 | wang | woman | 98 | 165 |
| 3 | chen | woman | 98 | 162 |
+----+-----------+-------+--------+--------+
3 rows in set (0.00 sec)
STRAIGHT_JOIN连接
STRAIGHT_JOIN并不是一个新的连接类型,而是用户对SQL优化器的控制,其等同于JOIN。通过STRAIGHT_JOIN,MySQL数据库会强制先读取左边的表。
MySQL [mysql_chuid]> explain select * from students_1 join students_2 on students_1.id=students_2.id;
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
| 1 | SIMPLE | students_1 | ALL | NULL | NULL | NULL | NULL | 3 | NULL |
| 1 | SIMPLE | students_2 | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
2 rows in set (0.01 sec)
MySQL [mysql_chuid]> explain select * from students_1 straight_join students_2 on students_1.id=students_2.id;
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
| 1 | SIMPLE | students_1 | ALL | NULL | NULL | NULL | NULL | 3 | NULL |
| 1 | SIMPLE | students_2 | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+------------+------+---------------+------+---------+------+------+----------------------------------------------------+
2 rows in set (0.00 sec)
# 当指定STRAIGHT_JOIN方式后,MySQL就会先选择students_1表,然后再进行匹配。
优点:在进行大量数据的访问时,我们指定STRAIGHT_JOIN让MySQL先读取左边的表,让MySQL按照我们的意愿来完成连接操作。在进行性能优化时,可以考虑使用STRAIGHT_JOIN。
子查询
子查询是MySQL中比较常用的查询方法,通过子查询可以实现多表查询。子查询指将一个查询语句嵌套在另一个查询语句中。子查询可以在SELECT、UPDATE和 DELETE语句中使用,而且可以进行多层嵌套。在实际开发时,子查询经常出现在WHERE子句中。
子查询在WHERE中的语法格式:WHERE <表达式> <操作符> (子查询)
其中,操作符可以是比较运算符和IN、NOT IN、EXISTS、NOT EXISTS等关键字。
1)IN | NOT IN
当表达式与子查询返回的结果集中的某个值相等时,返回TRUE,否则返回FALSE;若使用关键字NOT,则返回值正好相反。
2)EXISTS | NOT EXISTS
用于判断子查询的结果集是否为空,若子查询的结果集不为空,返回TRUE,否则返回FALSE;若使用关键字NOT,则返回的值正好相反。
MySQL [mysql_chuid]> select * from students;
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
| 3 | li | man | 132 | 169 | linux | 5 |
| 4 | liu | woman | 132 | 169 | NULL | 6 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 6 | luo | woman | 118 | 162 | linux | 8 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
8 rows in set (0.00 sec)
MySQL [mysql_chuid]> select * from students_5;
+----+-------+------+--------+--------+----------+----------+-------------+-----------+
| id | name | age | weight | height | birthday | address | course_name | course_ID |
+----+-------+------+--------+--------+----------+----------+-------------+-----------+
| 1 | chd | 27 | 129 | 170 | 10-16 | hubei | python | NULL |
| 2 | chuid | 25 | 129 | 170 | 10-8 | jiayu | linux | NULL |
| 3 | chen | 26 | 128 | 171 | 5-3 | shenzhen | java | NULL |
| 5 | zhang | 26 | 105 | 162 | 2-14 | shenzhen | java/linux | NULL |
| 6 | wang | 27 | 103 | 159 | 6-5 | NULL | java/c++ | NULL |
| 7 | liu | 27 | 102 | 158 | 8-6 | NULL | python | NULL |
| 8 | guo | 28 | 98 | 156 | 11-30 | hunan | linux | NULL |
+----+-------+------+--------+--------+----------+----------+-------------+-----------+
7 rows in set (0.00 sec)
# 查询students表和students_5表中学习python课程的姓名
MySQL [mysql_chuid]> SELECT name FROM students WHERE course_ID IN (SELECT id FROM students_5 WHERE course_name = 'python');
+------+
| name |
+------+
| chd |
| chen |
+------+
2 rows in set (0.00 sec)
# 执行内查询,查询students_5表中课程为Linux的id
MySQL [mysql_chuid]> SELECT id FROM students_5 WHERE course_name = 'linux';
+----+
| id |
+----+
| 2 |
| 8 |
+----+
2 rows in set (0.00 sec)
# 执行外层查询,在students表中查询course_id等于1的姓名
MySQL [mysql_chuid]> SELECT name FROM students WHERE course_id IN (1);
+------+
| name |
+------+
| chd |
+------+
1 row in set (0.00 sec)
* 习惯上,外层的SELECT查询称为父查询,圆括号中嵌入的查询称为子查询(子查询必须放在圆括号内)。MySQL在处理上例的SELECT语句时,执行流程为:先执行子查询,再执行父查询。
# 在SELECT语句中使用 NOT IN 关键字,查询没有学习python的姓名
MySQL [mysql_chuid]> SELECT name FROM students WHERE course_id NOT IN (SELECT id FROM students_5 WHERE course_name='python');
+-------+
| name |
+-------+
| wang |
| li |
| liu |
| anivd |
| luo |
| zhang |
+-------+
6 rows in set (0.00 sec)
# 使用=运算符,在students_5表和students表中查询出所有学习Python的姓名
MySQL [mysql_chuid]> SELECT name FROM students WHERE course_id = (SELECT id FROM students WHERE course_name = 'java');
+-------+
| name |
+-------+
| wang |
| anivd |
+-------+
2 rows in set (0.00 sec)
# 使用<>运算符,在students_5表和students表中查询出没有学习Python的姓名
MySQL [mysql_chuid]> SELECT name FROM students WHERE course_id <> (SELECT id FROM students WHERE course_name = 'java');
+-------+
| name |
+-------+
| chd |
| li |
| liu |
| luo |
| zhang |
| chen |
+-------+
6 rows in set (0.00 sec)
# 查询students_5表中是否存在id=1的记录,如果存在,就查询出students表中的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE EXISTS(SELECT course_name FROM students WHERE id=1);
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
| 3 | li | man | 132 | 169 | linux | 5 |
| 4 | liu | woman | 132 | 169 | NULL | 6 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 6 | luo | woman | 118 | 162 | linux | 8 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
8 rows in set (0.01 sec)
students_5表中存在id=1的记录,因此EXISTS表达式返回TRUE,外层查询语句接收TRUE之后对表students进行查询,返回所有的记录。
# 查询students_5表中是否存在id=1的记录,如果存在,就查询出students表中height字段大于169的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE height>169 AND EXISTS(SELECT course_name FROM students WHERE id=1);
+----+-------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+------+--------+--------+-------------+-----------+
3 rows in set (0.00 sec)
从students表中查询出了一条记录,这条记录的height字段取值为169。内层查询语句从students_5表中查询到记录,返回TRUE。外层查询语句开始进行查询。根据查询条件,从students表中查询height大于169的记录。
* 子查询的功能也可以通过表连接完成,但是子查询会使SQL语句更容易阅读和编写。
* 一般来说,表连接(内连接和外连接等)都可以用子查询替换,但反过来却不一定,有的子查询不能用表连接来替换。子查询比较灵活、方便、形式多样,适合作为查询的筛选条件,而表连接更适合于查看连接表的数据。
子查询注意事项
在完成较复杂的数据查询时,经常会使用到子查询,编写子查询语句时,要注意如下事项:
1) 子查询语句可以嵌套在SQL语句中任何表达式出现的位置
在SELECT语句中,子查询可以被嵌套在SELECT语句的列、表和查询条件中,即SELECT子句,FROM子句、WHERE子句、GROUP BY子句和HAVING子句。
前面已经介绍了WHERE子句中嵌套子查询的使用方法,下面是子查询在SELECT子句和FROM子句中的使用语法。
嵌套在SELECT语句的SELECT子句中的子查询语法格式:
SELECT(子查询)FROM表名;
* 子查询结果为单行单列,但不必指定列别名。
嵌套在 SELECT 语句的 FROM 子句中的子查询语法格式:
SELECT * FROM (子查询) AS 表的别名;
* 必须为表指定别名。一般返回多行多列数据记录,可以当作一张临时表。
2) 只出现在子查询中而没有出现在父查询中的表不能包含在输出列中
多层嵌套子查询的最终数据集只包含父查询(即最外层的查询)的SELECT子句中出现的字段,而子查询的输出结果通常会作为其外层子查询数据源或用于数据判断匹配。
常见错误:SELECT * FROM (SELECT * FROM result);
这个子查询语句产生语法错误的原因在于主查询语句的FROM子句是一个子查询语句,因此应该为子查询结果集指定别名。
正确代码:SELECT * FROM (SELECT * FROM result) AS Temp;
正则表达式查询
REGEXP关键字指定正则表达式的字符匹配模式,基本语法格式:属性名 REGEXP '匹配方式'。
其中,“属性名”表示需要查询的字段名称;“匹配方式”表示以哪种方式来匹配查询。“匹配方式”中有很多的模式匹配字符,它们分别表示不同的意思。
MySQL中的正则表达式与Java语言、PHP语言等编程语言中的正则表达式基本一致。
选项 | 说明 | 例子 | 匹配值示例 |
^ | 匹配文本的开始字符 | '^b' 匹配以字母 b 开头的字符串 | Book |
$ | 匹配文本的结束字符 | 'st$' 匹配以 st 结尾的字符串 | test |
. | 匹配任何单个字符 | 'b.t' 匹配任何 b 和 t 之间有一个字符 | bat |
* | 匹配零个或多个在它面前的字符 | 'f*n' 匹配字符 n 前面有任意个字符 f | fan |
+ | 匹配前面的字符1次或多次 | 'ba+' 匹配以 b 开头,后面至少紧跟一个 a | battle |
<字符串> | 匹配包含指定字符的文本 | 'fa' 匹配包含‘fa’的文本 | fan |
[字符合集] | 匹配字符集合中的任何一个字符 | '[xz]' 匹配 x 或者 z | x-ray |
[^] | 匹配不在括号中的任何字符 | '[^abc]' 匹配任何不包含 a、b 或 c 的字符串 | desk |
字符串{n} | 匹配前面的字符串至少n次 | 'b{2}' 匹配 2 个或更多的 b | bbb |
字符串{n,m} | 匹配前面的字符串至少n次,至多m次 | 'b{2,4}' 匹配最少 2 个,最多 4 个 b | bbb |
查询以特定字符或字符串开头的记录
字符 ^ 用来匹配以特定字符或字符串开头的记录。
# 在students表中,查询name字段以“c”开头的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP '^c';
+----+------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+------+------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+------+------+--------+--------+-------------+-----------+
2 rows in set (0.10 sec)
查询以特定字符或字符串结尾的记录
字符 $ 用来匹配以特定字符或字符串结尾的记录。
# 在students表中,查询name字段以“d”结尾的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'd$';
+----+-------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 5 | anivd | man | 130 | 171 | python | 2 |
+----+-------+------+--------+--------+-------------+-----------+
2 rows in set (0.00 sec)
替代字符串中的任意一个字符
字符 . 用来替代字符串中的任意一个字符。
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'c.d';
+----+------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+------+------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
+----+------+------+--------+--------+-------------+-----------+
1 row in set (0.00 sec)
# 在students表中,查询name字段值包含“h”和“n”,且两个字母之间只有一个字母的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'h.n';
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
2 rows in set (0.00 sec)
匹配多个字符
字符 * 和 + 都可以匹配多个该符号之前的字符。不同的是,+ 表示至少一个字符,而 * 可以表示0个字符。
# 在students表中,查询name字段值包含字母“c”,且“c”后面出现字母“h”的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP '^ch*';
+----+------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+------+------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+------+------+--------+--------+-------------+-----------+
2 rows in set (0.00 sec)
# 在students表中,查询name字段值包含字母“a”,且“a”后面至少出现“n”一次的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP '^an+';
+----+-------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+------+--------+--------+-------------+-----------+
| 5 | anivd | man | 130 | 171 | python | 2 |
+----+-------+------+--------+--------+-------------+-----------+
1 row in set (0.00 sec)
匹配指定字符串
正则表达式可以匹配字符串。当表中的记录包含这个字符串时,就可以将该记录查询出来。指定多个字符串时,需要用|隔开。只要匹配这些字符串中的任意一个即可。
# 在students表中,查询name字段值包含字符串“an”的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'an';
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 2 | wang | woman | 105 | 165 | java | 2 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
+----+-------+-------+--------+--------+-------------+-----------+
3 rows in set (0.00 sec)
# 在students表中,查询name字段值包含字符串“an”或“ch”的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'an|ch';
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
5 rows in set (0.00 sec)
* 字符串与|之间不能有空格。因为,查询过程中,数据库系统会将空格也当作一个字符,这样就查询不出想要的结果。
匹配指定字符串中的任意一个
使用方括号[ ]可以将需要查询的字符组成一个字符集合。只要记录中包含方括号中的任意字符,该记录就会被查询出来。
例如,通过“[abc]”可以查询包含 a、b 和 c 等 3 个字母中任意一个的记录。
# 在students表中,查询name字段值包含字母“h”或“n”的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP '[hn]';
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
5 rows in set (0.00 sec)
* 方括号[ ]还可以指定集合的区间。例如,“[a-z]”表示从 a~z 的所有字母;“[0-9]”表示从 0~9 的所有数字;“[a-z0-9]”表示包含所有的小写字母和数字;“[a-zA-Z]”表示匹配所有字符。
# 在students表中,查询id字段值中包含1或2的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE id REGEXP '[12]';
+----+------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
+----+------+-------+--------+--------+-------------+-----------+
2 rows in set (0.01 sec)
匹配指定字符以外的字符
[^字符集合]用来匹配不在指定集合中的任何字符。
# 在students表中,查询 name 字段值包含字母 a~n 以外的字符的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP '[^a~n]';
+----+-------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+-------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 2 | wang | woman | 105 | 165 | java | 2 |
| 3 | li | man | 132 | 169 | linux | 5 |
| 4 | liu | woman | 132 | 169 | NULL | 6 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 6 | luo | woman | 118 | 162 | linux | 8 |
| 7 | zhang | woman | 98 | 162 | java/linux | 9 |
| 8 | chen | man | 130 | 170 | python | 7 |
+----+-------+-------+--------+--------+-------------+-----------+
8 rows in set (0.00 sec)
使用{n,}或者{n,m}来指定字符串连续出现的次数
字符串{n,}表示字符串连续出现 n 次;字符串{n,m}表示字符串连续出现最少 n 次,最多 m 次。
例如,a{2,}表示字母a连续出现至少2次,也可以大于2次;a{2,4} 表示字母a连续出现最少2次,最多不能超过4次。
# 在students表中,查询name字段值出现字母“h”至少2次的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'h{2,}';
+----+------+------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+------+------+--------+--------+-------------+-----------+
| 12 | chh | man | 132 | 171 | python | 8 |
+----+------+------+--------+--------+-------------+-----------+
1 row in set (0.00 sec)
# 在students表中,查询name字段值出现字母“d”最少1次,最多3次的记录
MySQL [mysql_chuid]> SELECT * FROM students WHERE name REGEXP 'd{1,3}';
+----+----------+-------+--------+--------+-------------+-----------+
| id | name | sex | weight | height | course_name | course_ID |
+----+----------+-------+--------+--------+-------------+-----------+
| 1 | chd | man | 130 | 171 | python | 1 |
| 5 | anivd | man | 130 | 171 | python | 2 |
| 9 | chenhuid | woman | 102 | 168 | python | 3 |
+----+----------+-------+--------+--------+-------------+-----------+
3 rows in set (0.00 sec)