子查询
指把一个查询语句嵌套在另一个查询语句中
SELECT 字段名称,... FROM tbl_name1 WHERE col_name1=(SELECT col_name2 FROM tbl_name2)
我们可以看到有两层查询结果,内层查询语句的结果可以作为外层查询语句的条件。
由[NOT] IN引发的子查询
SELECT 字段名称,... FROM tbl_name WHERE col_name [NOT] IN (条件)
由比较运算符引出的子查询
SELECT 字段名称,... FROM tbl_name WHERE col_name 比较运算符(条件)
由EXISTS引发的子查询
如果内层查询查到了结果存在,那么返回的是真值,也就执行外层查询;不然的话返回的是假值,不执行外层查询。
SELECT 字段名称,... FROM tbl_name WHERE col_name EXISTS(内层查询)
由ANY SOME ALL引发的子查询
我们来稍微解释几个。
>=ANY表示大于等于内层查询的最小值。也就是大于等于内层查询的任意一个。
>=SOME表示大于等于最小值。也就是大于等于内层查询的有一些。
>=ALL代表大于等于内层查询的最大值。也就是大于等于内层查询的每一个
SELECT 字段名称,... FROM tbl_name WHERE col_name 关系运算符 ANY|SOME|ALL(内层查询);
由子查询带来的一些语句
INSERT … SELECT
将查询出来的结果写入到表中。包括INSERT … SET和UPDATE … SET 的形式都可以使用到我们的子查询。实现数据的导入。
CREATE … SELECT
在创建表时将另外一个表中的数据写入到表中。实现数据的导入。
CREATE TABLE tbl_name(
...
)SELECT 字段名称,... FROM emp;
-- 创建表结构一样的表
CREATE TABLE tbl_name1 LIKE tbl_name2;
测试
测试子查询
测试由IN引发的子查询
下面是测试用表的内容
SELECT * FROM emp;
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 1 | king | 25 | 保密 | 北京 | 1 |
| 2 | queen | 26 | 保密 | 北京 | 2 |
| 3 | imooc | 27 | 保密 | 北京 | 1 |
| 4 | lily | 28 | 保密 | 北京 | 1 |
| 5 | rose | 29 | 保密 | 北京 | 3 |
| 6 | john | 30 | 保密 | 北京 | 3 |
| 7 | 测试用户 | 39 | 保密 | 北京 | 6 |
+----+----------+-----+------+------+-------+
SELECT * FROM dep;
+----+---------------+-----------------+
| id | depName | depDesc |
+----+---------------+-----------------+
| 1 | PHP教学部 | 研发PHP课件 |
| 2 | JAVA教学部 | 研发JAVA课件 |
| 3 | WEB前端教学部 | 研发WEB前端课件 |
| 4 | IOS教学部 | 研发IOS课件 |
+----+---------------+-----------------+
查询出emp表中的depId在dep表中有对应的记录
SELECT * FROM emp WHERE depID IN(1,2,3,4);
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 1 | king | 25 | 保密 | 北京 | 1 |
| 2 | queen | 26 | 保密 | 北京 | 2 |
| 3 | imooc | 27 | 保密 | 北京 | 1 |
| 4 | lily | 28 | 保密 | 北京 | 1 |
| 5 | rose | 29 | 保密 | 北京 | 3 |
| 6 | john | 30 | 保密 | 北京 | 3 |
+----+----------+-----+------+------+-------+
我们可以发现在上面IN的括号中就是dep表中id的值,我们可以替换一下里面已有的内容,改成查询语句
SELECT * FROM emp WHERE depId IN(SELECT id FROM dep);
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 1 | king | 25 | 保密 | 北京 | 1 |
| 2 | queen | 26 | 保密 | 北京 | 2 |
| 3 | imooc | 27 | 保密 | 北京 | 1 |
| 4 | lily | 28 | 保密 | 北京 | 1 |
| 5 | rose | 29 | 保密 | 北京 | 3 |
| 6 | john | 30 | 保密 | 北京 | 3 |
+----+----------+-----+------+------+-------+
还可以使用NOT IN
SELECT * FROM emp WHERE depId NOT IN(SELECT id FROM dep);
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 7 | 测试用户 | 39 | 保密 | 北京 | 6 |
+----+----------+-----+------+------+-------+
测试由比较运算符引出的子查询
-- 创建学院表
CREATE TABLE IF NOT EXISTS stu(
id TINYINT UNSIGNED AUTO_INCREMENT KEY COMMENT '编号',
username VARCHAR(20) NOT NULL UNIQUE COMMENT '学院名称',
score TINYINT UNSIGNED NOT NULL COMMENT '学院考试分数'
);
INSERT stu(username,score) VALUES('king',95),
('queen',75),
('zhangsan',69),
('lisi',78),
('wangwu',87),
('zhaoliu',88),
('tianqi',98),
('ceshi',99),
('tiancai',50);
-- 创建分数基本表
CREATE TABLE IF NOT EXISTS level(
id TINYINT UNSIGNED KEY AUTO_INCREMENT COMMENT '编号',
score TINYINT UNSIGNED COMMENT '分数'
);
INSERT level(score) VALUES(90),
(80),
(70);
-- 查询出成绩优秀的学员
SELECT id,username,score FROM stu
WHERE score>=(SELECT score FROM level WHERE id=1);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
+----+----------+-------+
-- 查询出没有得到评级的学员
SELECT id,username,score FROM stu
WHERE score<=(SELECT score FROM level WHERE id=3);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 3 | zhangsan | 69 |
| 9 | tiancai | 50 |
+----+----------+-------+
测试由EXISTS引发的子查询
下面是测试表的内容
SELECT * FROM emp;
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 1 | king | 25 | 保密 | 北京 | 1 |
| 2 | queen | 26 | 保密 | 北京 | 2 |
| 3 | imooc | 27 | 保密 | 北京 | 1 |
| 4 | lily | 28 | 保密 | 北京 | 1 |
| 5 | rose | 29 | 保密 | 北京 | 3 |
| 6 | john | 30 | 保密 | 北京 | 3 |
| 7 | 测试用户 | 39 | 保密 | 北京 | 6 |
+----+----------+-----+------+------+-------+
SELECT * FROM dep;
+----+---------------+-----------------+
| id | depName | depDesc |
+----+---------------+-----------------+
| 1 | PHP教学部 | 研发PHP课件 |
| 2 | JAVA教学部 | 研发JAVA课件 |
| 3 | WEB前端教学部 | 研发WEB前端课件 |
| 4 | IOS教学部 | 研发IOS课件 |
+----+---------------+-----------------+
对于下面语句的内查询,显然是不存在的。
SELECT * FROM emp WHERE EXISTS(SELECT depName FROM dep WHERE id=10);
Empty set
对于下面语句的内查询,显然是存在的,外查询也就执行了。
SELECT * FROM emp WHERE EXISTS(SELECT depName FROM dep WHERE id=1);
+----+----------+-----+------+------+-------+
| id | username | age | sex | addr | depId |
+----+----------+-----+------+------+-------+
| 1 | king | 25 | 保密 | 北京 | 1 |
| 2 | queen | 26 | 保密 | 北京 | 2 |
| 3 | imooc | 27 | 保密 | 北京 | 1 |
| 4 | lily | 28 | 保密 | 北京 | 1 |
| 5 | rose | 29 | 保密 | 北京 | 3 |
| 6 | john | 30 | 保密 | 北京 | 3 |
| 7 | 测试用户 | 39 | 保密 | 北京 | 6 |
+----+----------+-----+------+------+-------+
测试由ANY|SOME|ALL引发的子查询
下面是测试表的内容
SELECT * FROM stu;
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 2 | queen | 75 |
| 3 | zhangsan | 69 |
| 4 | lisi | 78 |
| 5 | wangwu | 87 |
| 6 | zhaoliu | 88 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
| 9 | tiancai | 50 |
+----+----------+-------+
SELECT * FROM level;
+----+-------+
| id | score |
+----+-------+
| 1 | 90 |
| 2 | 80 |
| 3 | 70 |
+----+-------+
ANY
SELECT * FROM stu
WHERE score>=ANY(SELECT score FROM LEVEL);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 2 | queen | 75 |
| 4 | lisi | 78 |
| 5 | wangwu | 87 |
| 6 | zhaoliu | 88 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
+----+----------+-------+
SELECT * FROM stu
WHERE score=ANY(SELECT score FROM level);
Empty set
SOME
SELECT * FROM stu
WHERE score>=SOME(SELECT score FROM LEVEL);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 2 | queen | 75 |
| 4 | lisi | 78 |
| 5 | wangwu | 87 |
| 6 | zhaoliu | 88 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
+----+----------+-------+
ALL
SELECT * FROM stu
WHERE score>=ALL(SELECT score FROM LEVEL);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
+----+----------+-------+
SELECT * FROM stu
WHERE score<ALL(SELECT score FROM level);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 3 | zhangsan | 69 |
| 9 | tiancai | 50 |
+----+----------+-------+
SELECT * FROM stu
WHERE score!=ALL(SELECT score FROM level);
+----+----------+-------+
| id | username | score |
+----+----------+-------+
| 1 | king | 95 |
| 2 | queen | 75 |
| 3 | zhangsan | 69 |
| 4 | lisi | 78 |
| 5 | wangwu | 87 |
| 6 | zhaoliu | 88 |
| 7 | tianqi | 98 |
| 8 | ceshi | 99 |
| 9 | tiancai | 50 |
+----+----------+-------+
测试CREATE … INSERT 和 INSERT … SELECT
-- 创建一个user4表,将emp表中的id username字段插入到新建的user4表中
CREATE TABLE user4(
id INT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20)
)SELECT id,username FROM emp;
mysql> SELECT * FROM user4;
+----+----------+
| id | username |
+----+----------+
| 1 | king |
| 2 | queen |
| 3 | imooc |
| 4 | lily |
| 5 | rose |
| 6 | john |
| 7 | 测试用户 |
+----+----------+
-- 将user3表中的用户名表写入到user4表中
INSERT user4(username) SELECT username FROM user3;
SELECT * FROM user3;
+----+----------+------------+-------+
| id | username | email | proId |
+----+----------+------------+-------+
| 1 | a | 123@qq.com | 1 |
| 2 | b | 123@qq.com | 1 |
| 3 | c | 123@qq.com | 1 |
| 4 | d | 123@qq.com | 2 |
| 5 | e | 123@qq.com | 3 |
| 6 | f | 123@qq.com | 1 |
| 7 | g | 123@qq.com | 1 |
+----+----------+------------+-------+
SELECT * FROM user4;
+----+----------+
| id | username |
+----+----------+
| 1 | king |
| 2 | queen |
| 3 | imooc |
| 4 | lily |
| 5 | rose |
| 6 | john |
| 7 | 测试用户 |
| 8 | a |
| 9 | b |
| 10 | c |
| 11 | d |
| 12 | e |
| 13 | f |
| 14 | g |
+----+----------+
由这两条语句实现数据的导入
-- 创建表结构与user4一样的表user5
-- 注意刚创建完的表是一个空表
CREATE TABLE user5 LIKE user4;
-- 将user4中的数据导入user5
INSERT user5 SELECT id,username FROM user4;
SELECT * FROM user5;
+----+----------+
| id | username |
+----+----------+
| 1 | king |
| 2 | queen |
| 3 | imooc |
| 4 | lily |
| 5 | rose |
| 6 | john |
| 7 | 测试用户 |
| 8 | a |
| 9 | b |
| 10 | c |
| 11 | d |
| 12 | e |
| 13 | f |
| 14 | g |
+----+----------+
接下来用 INSERT … SET 加上子查询 来实现一下导入数据
INSERT user5 SET username=(SELECT username FROM stu WHERE id=9);
SELECT * FROM user5;
+----+----------+
| id | username |
+----+----------+
| 1 | king |
| 2 | queen |
| 3 | imooc |
| 4 | lily |
| 5 | rose |
| 6 | john |
| 7 | 测试用户 |
| 8 | a |
| 9 | b |
| 10 | c |
| 11 | d |
| 12 | e |
| 13 | f |
| 14 | g |
| 15 | tiancai |
+----+----------+
并且因为user5的username字段并不是唯一的,所以我们可以插入重复的值,我们再次执行上面那条插入语句,来介绍一下另一个东东
| 15 | tiancai |
| 16 | tiancai |
+----+----------+
-- 去除重复的记录
SELECT DISTINCT(username) FROM user5;
+----------+
| username |
+----------+
| king |
| queen |
| imooc |
| lily |
| rose |
| john |
| 测试用户 |
| a |
| b |
| c |
| d |
| e |
| f |
| g |
| tiancai |
+----------+
但是实际上它并没有真的去除掉重复值,只是在这一次查询中去除掉了。