牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0
牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010666669/article/details/104763370
牛客网数据库SQL实战解析(11-20题): https://blog.csdn.net/u010666669/article/details/104863298
牛客网数据库SQL实战解析(21-30题): https://blog.csdn.net/u010666669/article/details/104871373
牛客网数据库SQL实战解析(31-40题): https://blog.csdn.net/u010666669/article/details/104977904
牛客网数据库SQL实战解析(41-50题): https://blog.csdn.net/u010666669/article/details/104979427
牛客网数据库SQL实战解析(51-61题): https://blog.csdn.net/u010666669/article/details/104980372
51. 查找字符串'10,A,B' 中逗号','出现的次数cnt。
SELECT (length("10,A,B")-length(replace("10,A,B",",","")))/length(",") AS cnt ;
解析:找出所有,的长度,再除以一个,的长度。
52. 获取Employees中的first_name,查询按照first_name最后两个字母,按照升序进行排列
SELECT first_name
FROM employees
ORDER BY substr(first_name,length(first_name)-1)
;
题解二:
SELECT first_name FROM employees ORDER BY substr(first_name,-2);
解析:字符串截取,substring()。
53. 按照dept_no进行汇总,属于同一个部门的emp_no按照逗号进行连接,结果给出dept_no以及连接出的结果employees
SELECT dept_no, group_concat(emp_no) AS employees
FROM dept_emp GROUP BY dept_no
;
解析:聚合函数group_concat(X,Y),其中X是要连接的字段,Y是连接时用的符号,可省略,默认为逗号。此函数必须与 GROUP BY 配合使用。此题以 dept_no 作为分组,将每个分组中不同的emp_no用逗号连接起来(即可省略Y)。
54. 查找排除当前最大、最小salary之后的员工的平均工资avg_salary。
SELECT AVG(salary) AS avg_salary FROM salaries
WHERE to_date = '9999-01-01'
AND salary NOT IN (SELECT MAX(salary) FROM salaries)
AND salary NOT IN (SELECT MIN(salary) FROM salaries)
;
解析:这题逻辑很简单。
55. 分页查询employees表,每5行一页,返回第2页的数据
SELECT * FROM employees LIMIT 5,5 ;
解析:分页可以通过limit来实现:limit x, y: x:表示偏移量, y:表示获取的数据数量
56. 获取所有员工的emp_no、部门编号dept_no以及对应的bonus类型btype和received ,没有分配具体的员工不显示
SELECT de.emp_no, de.dept_no, eb.btype, eb.recevied
FROM dept_emp AS de LEFT JOIN emp_bonus AS eb
ON de.emp_no = eb.emp_no
;
解析:一个无聊的题。
57. 使用含有关键字exists查找未分配具体部门的员工的所有信息。
SELECT *
FROM employees
WHERE NOT EXISTS(
SELECT emp_no
FROM dept_emp
WHERE emp_no = employees.emp_no
)
;
解析:exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当 exists里的条件语句能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,返回当前loop到的这条记录;反之如果exists里的条 件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,当能返回结果集则为true,不能返回结果集则为 false。
58. 获取employees中的行数据,且这些行也存在于emp_v中。注意不能使用intersect关键字。
SELECT em.*
FROM employees em, emp_v ev
WHERE em.emp_no = ev.emp_no
;
解析:。。。
59. 获取有奖金的员工相关信息。
SELECT e.emp_no,
e.first_name,
e.last_name,
b.btype,
s.salary,
(CASE b.btype
WHEN 1 THEN s.salary * 0.1
WHEN 2 THEN s.salary * 0.2
ELSE s.salary * 0.3 END) AS bonus
FROM employees AS e
INNER JOIN emp_bonus AS b
ON e.emp_no = b.emp_no
INNER JOIN salaries AS s
ON e.emp_no = s.emp_no AND s.to_date = '9999-01-01'
;
解析:CASE 表达式的用法。即当 btype = 1 时,得到 salary * 0.1;当 btype = 2 时,得到 salary * 0.2;其他情况得到 salary * 0.3。
60. 按照salary的累计和running_total,其中running_total为前两个员工的salary累计和,其他以此类推。
SELECT s1.emp_no,
s1.salary,
(SELECT SUM(s2.salary)
FROM salaries AS s2
WHERE s2.emp_no <= s1.emp_no AND s2.to_date = '9999-01-01') AS running_total
FROM salaries AS s1
WHERE s1.to_date = '9999-01-01'
ORDER BY s1.emp_no
;
解析:输出的第三个字段,是由一个 SELECT 子查询构成。将子查询内复用的 salaries 表记为 s2,主查询的 salaries 表记为 s1,当主查询的 s1.emp_no 确定时,对子查询中不大于 s1.emp_no 的 s2.emp_no 所对应的薪水求和。
61. 对于employees表中,给出奇数行的first_name
SELECT first_name FROM (
SELECT e2.first_name,
( SELECT COUNT(*)
FROM employees e1
WHERE e1.first_name <= e2.first_name
) AS rownum
FROM employees e2
WHERE rownum % 2 =1
) t
;
解析:计算行号的方法 : 有多少个小于等于e2.first_name的记录的个数就是e2.first_name的行号