啃下这50道笔试题,你就是SQL专家!(附答案,收藏备用)
【关注微信公众号:跟强哥学SQL,回复“笔试”免费领取大厂SQL笔试题。】
有两个名为Department(部门)和Employees(员工)的表结构如下:
CREATE TABLE Department (
DepId int,
DepName varchar (255),
ParentDepID int
);
CREATE TABLE Employees (
ID int,
Name varchar (255),
Age int,
Birthday date,
Address varchar (255),
Salary decimal (18, 2),
ManagerId int,
DepID int
);
题目1:插入数据
题目:在Employees表中插入一条数据,ID为1, Name为’TOM', Age为30,出生日期为1990年3月10日,Address为’Guangzhou',Salary为8000,ManagerId为3,DepID为1。
答案:
INSERT INTO Employees
VALUES (1, 'TOM', 30, 'Guangzhou', 8000.00, 3, 1);
或
INSERT INTO Employees (ID, Name, Age, Birthday, Address, Salary, ManagerId, DepID)
VALUES (1, 'TOM', 30, '1990-03-10', 'Guangzhou', 8000.00, 3, 1);
解析:这是基本的插入语句,可以将需要插入的值放在VALUES()内,字段顺序与TABLE定义顺序匹配。
题目2:修改数据
题目:更新Employees表中ID为1的员工的工资为9000。
答案:
UPDATE Employees
SET Salary = 9000
WHERE ID = 1;
解析:使用Update语句进行数据的更新。可以通过Where子句限定需要修改的行。
题目3:删除数据
题目:删除Employees表中ID为1的全部信息。
答案:
DELETE FROM Employees
WHERE ID = 1;
解析:使用DELETE语句删除特定的行,可以通过WHERE子句找到ID为1的行并删除。
题目4:单表查询
题目:查找Employees表中所有员工的ID和Name。
答案:
SELECT ID, Name
FROM Employees;
解析:使用SELECT语句实现单表查询,选择想要显示的字段名称。
题目5:条件查询
题目:查找Employees表中所有薪水大于1万的员工的ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000;
解析:使用WHERE语句,可以精确筛选出满足条件的数据。
题目6:组合条件查询(AND)
题目:查找Employees表中所有薪水大于1万且年龄在30岁及以下的员工的ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
AND Age <= 30;
解析:在WHERE语句中使用AND关键字组合多个条件,可以查询出同时满足多个条件的数据。
题目7:组合条件查询(OR)
题目:查找Employees表中所有薪水大于1万或年龄在30岁及以下的员工的ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
OR Age <= 30;
解析:在WHERE语句中使用OR关键字组合多个条件,可以查询出满足任意一个条件的数据。
题目8:复杂组合条件查询(AND + OR)
题目:查找Employees表中所有年龄在30岁及以下的员工中薪水大于3万或小于5000的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE (Salary > 30000
OR Salary < 5000)
AND Age <= 30;
解析:在WHERE语句中使用AND和OR关键字,可以实现多个条件的复杂组合,此时可以使用小括号将多个条件放在一起优先计算。
题目9:字段拼接
题目:查询Employees表,以“ID:Name”格式显示员工的ID、Name。
答案:
SELECT CAST(ID as CHAR) || ':' || Name
FROM Employees;
或
SELECT CONCAT(CAST(ID as CHAR), ':', Name)
FROM Employees;
解析:使用||或CONCAT可以将多个字符串值拼接在一起。注意,如果待拼接的值不是字符串类型,需要使用转换函数进行转换后拼接。
题目10:数值计算
题目:为所有员工加薪10%。
答案:
UPDATE Employees
SET Salary = Salary * 1.1;
解析:对于数值类字段,可以进行加、减、乘、除等数值计算。
题目11:数据分段
题目:以小于1万、1万至3万、3万以上显示所有员工的薪水区间而不是具体的薪水。
答案:
SELECT ID,
CASE WHEN Salary <= 10000 THEN '小于1万'
WHEN Salary >= 30000 THEN '3万以上'
ELSE '1万至3万' END
FROM Employees
解析:可以使用CASE WHEN关键字,对满足不同条件的值转换返回值。
题目12:多表查询(内连接)
题目:查询Employees表和Department表,显示员工的姓名、部门名称。
答案:
SELECT e.Name, d.DepName
FROM Employees e
INNER JOIN Department d
ON e.DepId = d.DepId;
解析:这是一个基础的内连接查询,用于组合来自两个或更多表的行。当关联属性在参与连接的两张表中都存在时,数据才返回。
题目13:多表查询(左连接)
题目:查询Employees表和Department表,显示员工的姓名、部门名称。即使某员工未归属到任意一个部门下,也需要显示。
答案:
SELECT e.Name, d.DepName
FROM Employees e
LEFT JOIN Department d
ON e.DepId = d.DepId;
解析:这是一个基础的左连接查询,用于组合来自两个或更多表的行。当关联属性在参与连接的右表中不存在时,左表的数据也会返回,但来自右表的属性会显示为NULL。
题目14:多表查询(右连接)
题目:查询Employees表和Department表,显示员工的姓名、部门名称。即使某员工未归属到任意一个部门下,也需要显示。
答案:
SELECT e.Name, d.DepName
FROM Department d
RIGHT JOIN Employees e
ON d.DepId = e.DepId;
解析:这是一个基础的右连接查询,它等价于题目6。
题目15:排序查询(升序)
题目:查询所有员工ID及员工姓名,并以薪水从低到高排序。
答案:
SELECT ID, Name
FROM Employees
ORDER BY Salary;
或
SELECT ID, Name
FROM Employees
ORDER BY Salary ASC;
解析:使用SELECT语句提取员工ID及员工姓名,并通过ORDER BY关键字按照薪水进行升序排序。
题目16:排序查询(降序)
题目:查询所有员工ID及员工姓名,并以薪水从高到低排序。
答案:
SELECT ID, Name
FROM Employees
ORDER BY Salary DESC;
解析:使用SELECT语句提取员工ID及员工姓名,并通过ORDER BY关键字按照薪水进行降序排序。
题目17:排序查询(组合排序)
题目:查询所有员工ID及员工姓名,并以薪水从高到低、员工ID从小到大排序。
答案:
SELECT ID, Name
FROM Employees
ORDER BY Salary DESC, ID ASC;
解析:使用SELECT语句提取员工ID及员工姓名,并通过ORDER BY关键字按照薪水降序、员工ID升序进行排序。
题目18:查询前N行
题目:查询所有员工ID及员工姓名,并以薪水从高到低排序,返回前10名。
答案:
SELECT ID, Name
FROM Employees
ORDER BY Salary DESC
LIMIT 10;
解析:使用LIMIT可以返回前N行。
题目19:分页查询
题目:查询所有员工ID及员工姓名,并以薪水从高到低排序,每10人为1页,返回第3页的数据。
答案:
SELECT ID, Name
FROM Employees
ORDER BY Salary DESC
LIMIT 20,10;
解析:使用LIMIT时,可以先指定跳过的行数,再指定返回的行数。
题目20:自关联
题目:查询所有员工ID、员工姓名以及经理ID、经理姓名。
答案:
SELECT a.ID, a.Name, a.ManagerId, b.Name
FROM Employees a
INNER JOIN Employees b
ON a.ManagerId = b.ID;
解析:自己与自己关联,被称为自关联。常用于上下级等层级关系的查询中。
题目21:集合运算(UNION)
题目:返回所有薪水大于1万或年龄小于30的员工ID、员工姓名。同时满足两个条件的员工,仅返回1条记录。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
UNION
SELECT ID, Name
FROM Employees
WHERE Age < 30;
解析:使用UNION关键字,可以返回两个集合的并集。在返回之前会将相同的记录去重。
题目22:集合运算(UNION ALL)
题目:返回所有薪水大于1万或年龄小于30的员工ID、员工姓名。同时满足两个条件的员工,返回2条记录。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
UNION ALL
SELECT ID, Name
FROM Employees
WHERE Age < 30;
解析:使用UNION ALL关键字,可以返回两个集合的并集。在返回之前不会将相同的记录去重。
题目23:集合运算(EXCEPT或MINUS)
题目:返回薪水大于1万但年龄不小于30的员工ID、员工姓名。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
EXCEPT
SELECT ID, Name
FROM Employees
WHERE Age < 30;
解析:使用EXCEPT关键字,可以从一个集合中排除部分数据。
题目24:集合运算(INTERSECT)
题目:返回薪水大于1万且年龄小于30的员工ID、员工姓名。
答案:
SELECT ID, Name
FROM Employees
WHERE Salary > 10000
INTERSECT
SELECT ID, Name
FROM Employees
WHERE Age < 30;
解析:使用INTERSECT关键字,可以返回两个集合的交集。
题目25:模糊查询(包含关键字)
题目:查询所有名字中包含“磊”字的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Name LIKE '%磊%';
解析:LIKE关键字可以实现模糊查询,%通配符用来匹配任意多个任意字符。
题目26:模糊查询(以*开头)
题目:查询所有姓王的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Name LIKE '王%';
解析:使用LIKE关键字,可以查询出指定前缀字符的数据。
题目27:模糊查询(以*结尾)
题目:查询所有姓名最后一个字为“磊”的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Name LIKE '%磊';
解析:使用LIKE关键字,可以查询出指定后缀字符的数据。
题目28:模糊查询(第二个字符为指定符号)
题目:查询所有姓名第二个字为“磊”的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Name LIKE '_磊%';
解析:_下划线通配符用来匹配任意一个字符。
题目29:模糊查询(至少有3个字符)
题目:查询所有姓名至少为3个字的员工ID和Name。
答案:
SELECT ID, Name
FROM Employees
WHERE Name LIKE '___%';
解析:___三个下划线用来匹配任意3个字符。
题目30:子查询(IN)
题目:查询薪水在3万元以上的员工所在的部门ID和部门名称。
答案:
SELECT DepId, DepName
FROM Department
WHERE DepId IN (
SELECT DepID
FROM Employees
WHERE Salary > 30000
);
解析:使用IN关键字,可以查询存在于某个集合中的数据。
题目31:子查询(NOT IN)
题目:查询薪水在5000元以下的员工所在的部门ID和部门名称。
答案:
SELECT DepId, DepName
FROM Department
WHERE DepId NOT IN (
SELECT DepID
FROM Employees
WHERE Salary > 5000
);
解析:使用NOT IN关键字,可以查询不存在于某个集合中的数据。
题目32:子查询(EXISTS)
题目:查询薪水在3万元以上的员工所在的部门ID和部门名称。
答案:
SELECT DepId, DepName
FROM Department a
WHERE EXISTS (
SELECT 1
FROM Employees b
WHERE b.Salary > 30000
AND a.DepId = b.DepId
);
解析:使用EXISTS关键字,可以查询满足某些条件的数据。
题目33:子查询(NOT EXISTS)
题目:查询不存在薪水在3万元以上的员工的部门ID和部门名称。
答案:
SELECT DepId, DepName
FROM Department a
WHERE NOT EXISTS (
SELECT 1
FROM Employees b
WHERE b.Salary > 30000
AND a.DepId = b.DepId
);
解析:使用NOT EXISTS关键字,可以查询不满足某些条件的数据。
题目34:子查询(SELECT中的子查询)
题目:查询员工ID、员工姓名以及员工所在的部门ID和部门名称。
答案:
SELECT ID, Name, DepId,
(
SELECT b.DepName FROM Department b
WHERE a.DepId = b.DepId
)
FROM Employees a;
解析:在SELECT子句中也可以使用子查询。不过要注意,子查询中查询到满足条件的数据只能小于等于1条,否则查询可能会报错。
题目35:聚合函数(MIN)
题目:查询所有员工中的最小年龄。
答案:
SELECT MIN(Age)
FROM Employees a;
解析:使用聚合函数MIN,可以查询出最小值。
题目36:聚合函数(MAX)
题目:查询所有员工中的最大年龄。
答案:
SELECT MAX(Age)
FROM Employees a;
解析:使用聚合函数MAX,可以查询出最大值。
题目37:聚合函数(AVG)
题目:查询所有员工中的平均年龄。
答案:
SELECT AVG(Age)
FROM Employees a;
解析:使用聚合函数AVG,可以查询出平均值。
题目38:聚合函数(COUNT)
题目:查询总的员工。
答案:
SELECT COUNT(ID)
FROM Employees a;
或
SELECT COUNT(1)
FROM Employees a;
解析:使用聚合函数COUNT,可以对值进行计数(计数时,不计算NULL值)。
题目39:聚合函数(SUM)
题目:查询所有员工的总薪水。
答案:
SELECT SUM(Salary)
FROM Employees a;
解析:使用聚合函数SUM,可以对数值进行求和。
题目40:分组聚合(GROUP BY)
题目:查询每个部门下所有员工的总薪水。
答案:
SELECT DepId,SUM(Salary)
FROM Employees a
GROUP BY DepId;
解析:使用GROUP BY关键字及聚合函数,可以实现将相同部门的员工分组后聚合。
题目41:对聚合结果进行筛选(HAVING)
题目:查询平均薪水大于3万的部门。
答案:
SELECT DepId,SUM(Salary)
FROM Employees a
GROUP BY DepId
HAVING SUM(Salary) > 30000;
解析:使用HAVING关键字,可以对聚合后的结果进行筛选。
题目42:极值查询(查询最大值)
题目:查询薪水最大的所有员工。
答案:
SELECT *
FROM Employees a
WHERE Salary IN (
SELECT MAX(Salary) FROM Employees
);
解析:先查出最大值,然后再筛选薪水为最大值的员工。
题目43:极值查询(查询最小值)
题目:查询薪水最少的所有员工。
答案:
SELECT *
FROM Employees a
WHERE Salary IN (
SELECT MIN(Salary) FROM Employees
);
解析:先查出最小值,然后再筛选薪水为最小值的员工。
题目44:分析函数(ROW_NUMBER)
题目:查询每个部门薪水前3名的员工。即使薪水相同,也只返回前3名。
答案:
SELECT ID,RN
FROM (
SELECT
ID,
ROW_NUMBER() OVER(PARTITION BY DepId ORDER BY Salary DESC) RN
FROM Employees
)a
WHERE RN <= 3;
解析:先使用PARTITION BY关键字按部门分组,再使用ROW_NUMBER和ORDER BY计算出每位员工的排名,最后只筛选出前3名。当薪水相同时,随机排名,所以返回的排名是连续且不重复的。
题目45:分析函数(RANK)
题目:查询每个部门薪水前3名的员工。薪水相同,返回的排名相同,但只返回前3名。
答案:
SELECT ID,RN
FROM (
SELECT
ID,
RANK() OVER(PARTITION BY DepId ORDER BY Salary DESC) RN
FROM Employees
)a
WHERE RN <= 3;
解析:先使用PARTITION BY关键字按部门分组,再使用RANK和ORDER BY计算出每位员工的排名,最后只筛选出前3名。当薪水相同时,排名相同,但下一个排名序号将会被略过,所以返回的排名是不连续且重复的。
题目46:分析函数(DENSE_RANK)
题目:查询每个部门薪水前3名的员工。薪水相同,返回的排名相同,排名需连续。
答案:
SELECT ID,RN
FROM (
SELECT
ID,
DENSE_RANK() OVER(PARTITION BY DepId ORDER BY Salary DESC) RN
FROM Employees
)a
WHERE RN <= 3;
解析:先使用PARTITION BY关键字按部门分组,再使用DENSE_RANK和ORDER BY计算出每位员工的排名,最后只筛选出前3名。当薪水相同时,排名相同,且下一个排名序号不会被略过,所以返回的排名是连续且重复的。
题目47:去重(GROUP BY)
题目:查询每个部门下各有哪些年龄。
答案:
SELECT DepId,Age
FROM Employees
GROUP BY DepId,Age;
解析:GROUP BY关键字用于分组,同一分组因为数值相同,所以只返回一条记录。
题目48:去重(DISTINCT)
题目:查询每个部门下各有哪些年龄。
答案:
SELECT DISTINCT DepId,Age
FROM Employees
;
解析:DISTINCT关键字可以对指定的字段值直接进行去重。
题目49:随机采样查询
题目:从员工表中随机返回10条记录,要求每次返回的结果尽量随机分布。
答案:
SELECT *
FROM Employees
ORDER BY RAND()
LIMIT 10;
解析:RAND函数返回一个0~1之间的随机值,使用随机值排序,可以保证每次返回的行都是随机的。
题目50:日期函数转换
题目:统计出每个年份出生的员工数。
答案:
SELECT DATE_FORMAT(Birthday, '%Y'),count(*)
FROM Employees
GROUP BY DATE_FORMAT(Birthday, '%Y');
解析:Birthday字段的值为DATE类型,包含具体的年、月、日,所以在分组聚合前,需要使用DATE_FORMAT函数将DATE类型格式化取出年份后再统计。
【关注微信公众号:跟强哥学SQL,回复“笔试”免费领取大厂SQL笔试题。】