前言
手写SQL语句是笔试、面试中常见的题型,所以本篇主要收集一些常见的SQL笔试题。
实验环境
- MySQL 5.6 (Windows版)
第一篇
题目来源:某网站公开课(避免广告嫌疑,不具体指出)
答案来源:博主自己书写,仅供参考
表结构及数据
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`deptno` int(2) NOT NULL,
`dname` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`loc` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`deptno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NewYork');
INSERT INTO `dept` VALUES (20, 'RESEARCH', 'Dallas');
INSERT INTO `dept` VALUES (30, 'SALES', 'Chicago');
INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'Boston');
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(4) NOT NULL COMMENT '雇员编号',
`ename` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`job` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`mgr` int(4) NULL DEFAULT NULL,
`hiredate` date NULL DEFAULT NULL,
`sal` decimal(7, 0) NULL DEFAULT NULL,
`comm` decimal(7, 0) NULL DEFAULT NULL,
`deptno` int(2) NULL DEFAULT NULL,
PRIMARY KEY (`empno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, NULL, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, NULL, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, NULL, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, NULL, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-07-13', 3000, NULL, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000, NULL, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500, 0, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-07-13', 1100, NULL, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, NULL, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, NULL, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, NULL, 10);
-- ----------------------------
-- Table structure for salgrade
-- ----------------------------
DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (
`grade` int(7) NULL DEFAULT NULL,
`losal` int(7) NULL DEFAULT NULL,
`hisal` int(7) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of salgrade
-- ----------------------------
INSERT INTO `salgrade` VALUES (1, 700, 1200);
INSERT INTO `salgrade` VALUES (2, 1201, 1400);
INSERT INTO `salgrade` VALUES (3, 1401, 2000);
INSERT INTO `salgrade` VALUES (4, 2001, 3000);
INSERT INTO `salgrade` VALUES (5, 3001, 9999);
SET FOREIGN_KEY_CHECKS = 1;
部门平均薪水的等级
先求部门的平均薪水,再求这个薪水所处的等级
SELECT t.deptno, t.avgsal, s.`grade` FROM salgrade s
JOIN (
SELECT e.`deptno`, AVG(e.`sal`) AS avgsal FROM emp e
GROUP BY e.`deptno`
) t ON t.avgsal >= s.`losal` AND t.avgsal <= s.`hisal`
执行结果
+--------+-----------+-------+
| deptno | avgsal | grade |
+--------+-----------+-------+
| 10 | 2916.6667 | 4 |
| 20 | 2175.0000 | 4 |
| 30 | 1566.6667 | 3 |
+--------+-----------+-------+
部门薪水等级的平均值
先求每个部门每个员工的薪水等级,再求薪水等级的平均值
SELECT e.`deptno`, AVG(s.`grade`) AS avggrade
FROM emp e
LEFT JOIN salgrade s ON e.`sal` >= s.`losal` AND e.`sal` <= s.`hisal`
GROUP BY e.`deptno`
执行结果
+--------+----------+
| deptno | avggrade |
+--------+----------+
| 10 | 3.6667 |
| 20 | 2.8000 |
| 30 | 2.5000 |
+--------+----------+
哪些人是经理
emp
表中mgr
字段中所有的编号就是经理
SELECT DISTINCT m.`empno`, m.`ename`
FROM emp e
JOIN emp m ON e.`mgr` = m.`empno`
执行结果
+-------+-------+
| empno | ename |
+-------+-------+
| 7902 | FORD |
| 7698 | BLAKE |
| 7839 | KING |
| 7566 | JONES |
| 7788 | SCOTT |
| 7782 | CLARK |
+-------+-------+
不用组函数求最高薪水
利用ALL
关键字结合子查询,实现max
函数的效果
SELECT DISTINCT e.`sal` FROM emp e
WHERE e.`sal` >= ALL (SELECT e2.`sal` FROM emp e2)
执行结果
+------+
| sal |
+------+
| 5000 |
+------+
平均薪水最高的部门编号与名称
先求每个部门的平均薪水,再取平均薪水最高的部门信息
SELECT d.`deptno`, d.`dname` FROM dept d
JOIN (
SELECT t.deptno, MAX(t.avgsal) FROM (
SELECT e.`deptno`, AVG(e.`sal`) AS avgsal FROM emp e
GROUP BY e.`deptno`
) t
) o ON d.`deptno` = o.deptno
执行结果
+--------+------------+
| deptno | dname |
+--------+------------+
| 10 | ACCOUNTING |
+--------+------------+
平均薪水的等级最低的部门的部门名称
先求每个部门平均薪水的等级,再求等级最低的部门名称
SELECT d.`dname` FROM dept d
JOIN (
SELECT t.deptno, MIN(s.`grade`) FROM (
SELECT e.`deptno`, AVG(e.`sal`) AS avgsal FROM emp e
GROUP BY e.`deptno`
) t
LEFT JOIN salgrade s ON t.avgsal >= s.`losal` AND t.avgsal <= s.`hisal`
) o ON d.`deptno` = o.deptno
执行结果
+-------+
| dname |
+-------+
| SALES |
+-------+
比普通员工的最高薪水还要高的经理人名称
普通员工是指emp
表中mgr
列没有出现过的员工,先找出它们的最高薪水,再查询比这个最高薪水还高的经理人名称
SELECT e.`ename` FROM emp e
WHERE e.`empno` IN (SELECT j.`mgr` FROM emp j WHERE j.`mgr` IS NOT NULL)
AND e.`sal` > (
SELECT MAX(e.`sal`) FROM emp e
WHERE e.`empno` NOT IN (SELECT i.`mgr` FROM emp i WHERE i.`mgr` IS NOT NULL)
)
执行结果
+-------+
| ename |
+-------+
| FORD |
| BLAKE |
| KING |
| JONES |
| SCOTT |
| CLARK |
+-------+
第二篇
题目来源:同上
答案来源:同上
表结构及数据
CREATE TABLE S (
SNO INT PRIMARY KEY,
SNAME VARCHAR(10)
);
CREATE TABLE C(
CNO INT PRIMARY KEY,
CNAME VARCHAR(10),
CTEACHER VARCHAR(10)
);
CREATE TABLE SC(
SNO INT,
CNO INT,
SCGRADE INT
);
INSERT INTO s VALUES (1, 'zhangsan');
INSERT INTO s VALUES (2, 'lisi');
INSERT INTO s VALUES (3, 'wangwu');
INSERT INTO c VALUES (1, '数学', 'liming');
INSERT INTO c VALUES (2, '语文', 'liming');
INSERT INTO c VALUES (3, '历史', 'xueyou');
INSERT INTO c VALUES (4, '物理', 'guorong');
INSERT INTO c VALUES (5, '化学', 'liming');
INSERT INTO sc VALUES (1, 1, 59);
INSERT INTO sc VALUES (1, 2, 70);
INSERT INTO sc VALUES (2, 1, 30);
INSERT INTO sc VALUES (1, 3, 16);
INSERT INTO sc VALUES (2, 3, 61);
INSERT INTO sc VALUES (3, 1, 17);
INSERT INTO sc VALUES (3, 2, 100);
INSERT INTO sc VALUES (3, 5, 25);
INSERT INTO sc VALUES (1, 4, 99);
没选过"liming"老师的课的所有学生的名字
先找出选了liming
老师课的所有学生,再用NOT IN
关键字
SELECT s.sname FROM s WHERE s.sno NOT IN (
SELECT DISTINCT s.sno FROM s
LEFT JOIN sc ON s.sno = sc.sno
LEFT JOIN c ON sc.cno = c.cno
WHERE c.cteacher = 'liming'
)
执行结果
Empty set (0.00 sec)
2门以上(包括2门)不及格学生姓名及平均成绩
先找出2门不及格的学生的学号,再进行其他条件的判断
SELECT s.sname, AVG(sc.scgrade) AS avgscgrade FROM s
JOIN (
SELECT sc.sno FROM sc
WHERE sc.scgrade < 60
GROUP BY sc.sno
HAVING COUNT(*) > 1
) t ON s.sno = t.sno
JOIN sc ON sc.sno = s.sno
GROUP BY sc.sno
执行结果
+----------+------------+
| sname | avgscgrade |
+----------+------------+
| zhangsan | 61.0000 |
| wangwu | 47.3333 |
+----------+------------+
既学过1号课程又学过2号课程的学生的姓名
SELECT DISTINCT s.sname FROM sc
LEFT JOIN s ON sc.sno = s.sno
WHERE sc.sno IN (SELECT sc.sno FROM sc WHERE sc.cno = 1)
AND sc.sno IN (SELECT sc.sno FROM sc WHERE sc.cno = 2)
执行结果
+----------+
| sname |
+----------+
| zhangsan |
| wangwu |
+----------+