概念
子查询是将一个查询语句嵌套在另一个查询语句中。
1、内部嵌套其他select语句的查询,称为外查询或主查询
2、内层查询语句的查询结果,可以为外层查询语句提供查询条件。
3、子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
4、还可以包含比较运算符:= 、 !=、> 、<等
注:
1、子查询要包含在括号内。
2、将子查询放在比较条件的右侧。
3、单行操作符对应单行子查询,多行操作符对应多行子查询。
练习1
CREATE TABLE `emp` (
`empno` int(4) NOT NULL,
`ename` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`job` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`mgr` int(4) NULL DEFAULT NULL,
`hiredate` date NOT NULL,
`sai` int(255) NOT NULL,
`comm` int(255) NULL DEFAULT NULL,
`deptno` int(2) NOT NULL,
PRIMARY KEY (`empno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `emp` VALUES (1001, '甘宁', '文员', 1013, '2000-12-17', 8000, NULL, 20);
INSERT INTO `emp` VALUES (1002, '黛绮丝', '销售员', 1006, '2001-02-20', 16000, 3000, 30);
INSERT INTO `emp` VALUES (1003, '殷天正', '销售员', 1006, '2001-02-22', 12500, 5000, 30);
INSERT INTO `emp` VALUES (1004, '刘备', '经理', 1009, '2001-04-02', 29750, NULL, 20);
INSERT INTO `emp` VALUES (1005, '谢逊', '销售员', 1006, '2001-09-28', 12500, 14000, 30);
INSERT INTO `emp` VALUES (1006, '关羽', '经理', 1009, '2001-05-01', 28500, NULL, 30);
INSERT INTO `emp` VALUES (1007, '张飞', '经理', 1009, '2001-09-01', 24500, NULL, 10);
INSERT INTO `emp` VALUES (1008, '诸葛亮', '分析师', 1004, '2007-04-19', 30000, NULL, 20);
INSERT INTO `emp` VALUES (1009, '曾阿牛', '董事长', NULL, '2001-11-17', 50000, NULL, 10);
INSERT INTO `emp` VALUES (1010, '韦一笑', '销售员', 1006, '2001-09-08', 15000, 0, 30);
INSERT INTO `emp` VALUES (1011, '周泰', '文员', 1006, '2007-05-23', 11000, NULL, 20);
INSERT INTO `emp` VALUES (1012, '程普', '文员', 1006, '2001-12-03', 9500, NULL, 30);
INSERT INTO `emp` VALUES (1013, '庞统', '分析师', 1004, '2001-12-03', 30000, NULL, 20);
INSERT INTO `emp` VALUES (1014, '黄盖', '文员', 1007, '2002-01-23', 13000, NULL, 10);
INSERT INTO `emp` VALUES (1015, '张三', '保洁员', 1001, '2013-05-01', 80000, 50000, 50);
CREATE TABLE `dept` (
`deptno` int NOT NULL ,
`dname` char(9) NOT NULL ,
`loc` char(6) NOT NULL
);
INSERT INTO `dept` VALUES (10, '教研部', '北京');
INSERT INTO `dept` VALUES (20, '学工部', '上海');
INSERT INTO `dept` VALUES (30, '销售部', '广州');
INSERT INTO `dept` VALUES (40, '财务部', '武汉');
1、查询姓名和工资,要求工资=最低工资
mysql> select ename,sai from emp
-> where sai=(select min(sai) from emp);
+--------+------+
| ename | sai |
+--------+------+
| 甘宁 | 8000 |
+--------+------+
2、查询出高于10号部门的平均工资的员工信息
mysql> SELECT * FROM emp
-> WHERE sai>(SELECT AVG(sai) FROM emp
-> WHERE deptno=10);
+-------+-----------+-----------+------+------------+-------+-------+--------+
| empno | ename | job | mgr | hiredate | sai | comm | deptno |
+-------+-----------+-----------+------+------------+-------+-------+--------+
| 1004 | 刘备 | 经理 | 1009 | 2001-04-02 | 29750 | NULL | 20 |
| 1008 | 诸葛亮 | 分析师 | 1004 | 2007-04-19 | 30000 | NULL | 20 |
| 1009 | 曾阿牛 | 董事长 | NULL | 2001-11-17 | 50000 | NULL | 10 |
| 1013 | 庞统 | 分析师 | 1004 | 2001-12-03 | 30000 | NULL | 20 |
| 1015 | 张三 | 保洁员 | 1001 | 2013-05-01 | 80000 | 50000 | 50 |
+-------+-----------+-----------+------+------------+-------+-------+--------
3、查询出比10号部门任何员工薪资高的员工信息
mysql> SELECT * FROM emp
-> WHERE sai>(SELECT MAX(sai) FROM emp
-> WHERE deptno=10) AND deptno!=10;
+-------+--------+-----------+------+------------+-------+-------+--------+
| empno | ename | job | mgr | hiredate | sai | comm | deptno |
+-------+--------+-----------+------+------------+-------+-------+--------+
| 1015 | 张三 | 保洁员 | 1001 | 2013-05-01 | 80000 | 50000 | 50 |
+-------+--------+-----------+------+------------+-------+-------+--------+
4、查询出比10号部门任意一个员工薪资高的所有员工信息 : 只要比其中随便一个工资都可以
mysql> SELECT * FROM emp WHERE sai >ANY(SELECT sai FROM emp WHERE deptno = 10) AND deptno != 10;
+-------+-----------+-----------+------+------------+-------+-------+--------+
| empno | ename | job | mgr | hiredate | sai | comm | deptno |
+-------+-----------+-----------+------+------------+-------+-------+--------+
| 1002 | 黛绮丝 | 销售员 | 1006 | 2001-02-20 | 16000 | 3000 | 30 |
| 1004 | 刘备 | 经理 | 1009 | 2001-04-02 | 29750 | NULL | 20 |
| 1006 | 关羽 | 经理 | 1009 | 2001-05-01 | 28500 | NULL | 30 |
| 1008 | 诸葛亮 | 分析师 | 1004 | 2007-04-19 | 30000 | NULL | 20 |
| 1010 | 韦一笑 | 销售员 | 1006 | 2001-09-08 | 15000 | 0 | 30 |
| 1013 | 庞统 | 分析师 | 1004 | 2001-12-03 | 30000 | NULL | 20 |
| 1015 | 张三 | 保洁员 | 1001 | 2013-05-01 | 80000 | 50000 | 50 |
+-------+-----------+-----------+------+------------+-------+-------+--------+
5、获取员工的名字和部门的名字 select后面接子查询
mysql> SELECT ename,(SELECT dname FROM dept d WHERE d.deptno = e.deptno ) 部门名称 FROM emp e;
+-----------+--------------+
| ename | 部门名称 |
+-----------+--------------+
| 甘宁 | 学工部 |
| 黛绮丝 | 销售部 |
| 殷天正 | 销售部 |
| 刘备 | 学工部 |
| 谢逊 | 销售部 |
| 关羽 | 销售部 |
| 张飞 | 教研部 |
| 诸葛亮 | 学工部 |
| 曾阿牛 | 教研部 |
| 韦一笑 | 销售部 |
| 周泰 | 学工部 |
| 程普 | 销售部 |
| 庞统 | 学工部 |
| 黄盖 | 教研部 |
| 张三 | NULL |
+-----------+--------------+
6、查询emp表中所有管理层的信息 from后面接子查询
mysql> SELECT * FROM emp e,(SELECT DISTINCT mgr FROM emp) mgrtable WHERE e.empno = mgrtable.mgr;
+-------+-----------+-----------+------+------------+-------+------+--------+------+
| empno | ename | job | mgr | hiredate | sai | comm | deptno | mgr |
+-------+-----------+-----------+------+------------+-------+------+--------+------+
| 1013 | 庞统 | 分析师 | 1004 | 2001-12-03 | 30000 | NULL | 20 | 1013 |
| 1006 | 关羽 | 经理 | 1009 | 2001-05-01 | 28500 | NULL | 30 | 1006 |
| 1009 | 曾阿牛 | 董事长 | NULL | 2001-11-17 | 50000 | NULL | 10 | 1009 |
| 1004 | 刘备 | 经理 | 1009 | 2001-04-02 | 29750 | NULL | 20 | 1004 |
| 1007 | 张飞 | 经理 | 1009 | 2001-09-01 | 24500 | NULL | 10 | 1007 |
| 1001 | 甘宁 | 文员 | 1013 | 2000-12-17 | 8000 | NULL | 20 | 1001 |
+-------+-----------+-----------+------+------------+-------+------+--------+------+
练习2
CREATE TABLE `Authors` (
`ID` int(11) DEFAULT NULL,
`Name` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Authors` VALUES (1001,'张三'),(1002,'鸟哥'),(1003,'老男孩'),(1004,'刘江'),(1005,'刘天斯');
CREATE TABLE `Books` (
`ID` int(11) DEFAULT NULL,
`Author` int(11) DEFAULT NULL,
`Title` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Books` VALUES (101,1001,'MySQL从入门到精通'),(102,1001,'MySQL从入门到放弃'),(103,1002,'鸟哥的私房菜
基础篇'),(104,1002,'鸟哥的私房菜服务器篇'),(105,1003,'shell脚本编程'),(106,1004,'python21天速成'),(107,1004,'python web开发');
1) 请写一句 SQL,列出所有作者姓名和其所写书籍名称。
mysql> select Name,Title from Authors a left join Books b on a.ID=b.Author;
+-----------+--------------------------------+
| Name | Title |
+-----------+--------------------------------+
| 张三 | MySQL从入门到精通 |
| 张三 | MySQL从入门到放弃 |
| 鸟哥 | 鸟哥的私房菜基础篇 |
| 鸟哥 | 鸟哥的私房菜服务器篇 |
| 老男孩 | shell脚本编程 |
| 刘江 | python21天速成 |
| 刘江 | python web开发 |
| 刘天斯 | NULL |
+-----------+--------------------------------+
mysql> select Name,group_concat(Title) from Authors a left join Books b on a.ID=b.Author
-> group by name;
+-----------+------------------------------------------------------------+
| Name | group_concat(Title) |
+-----------+------------------------------------------------------------+
| 刘天斯 | NULL |
| 刘江 | python21天速成,python web开发 |
| 张三 | MySQL从入门到放弃,MySQL从入门到精通 |
| 老男孩 | shell脚本编程 |
| 鸟哥 | 鸟哥的私房菜基础篇,鸟哥的私房菜服务器篇 |
+-----------+------------------------------------------------------------+
2) 请写一句 SQL,列出写过两本以上(包括两本)书籍的作者姓名。
mysql> select name from Authors where id in(select author from Books group by author having count(1)>=2));
+--------+
| name |
+--------+
| 张三 |
| 鸟哥 |
| 刘江 |
+--------+