您的当前位置:首页正文

牛客网SQL练习题

2024-11-07 来源:个人技术集锦

01. 查找最晚入职员工的所有信息

DROP TABLE IF EXISTS `employees`;
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL, 
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));

INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
INSERT INTO employees VALUES(10003,'1959-12-03','Parto','Bamford','M','1986-08-28');
INSERT INTO employees VALUES(10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01');
INSERT INTO employees VALUES(10005,'1955-01-21','Kyoichi','Maliniak','M','1989-09-12');
INSERT INTO employees VALUES(10006,'1953-04-20','Anneke','Preusig','F','1989-06-02');
INSERT INTO employees VALUES(10007,'1957-05-23','Tzvetan','Zielinski','F','1989-02-10');
INSERT INTO employees VALUES(10008,'1958-02-19','Saniya','Kalloufi','M','1994-09-15');
INSERT INTO employees VALUES(10009,'1952-04-19','Sumant','Peac','F','1985-02-18');
INSERT INTO employees VALUES(10010,'1963-06-01','Duangkaew','Piveteau','F','1989-08-24');
INSERT INTO employees VALUES(10011,'1953-11-07','Mary','Sluis','F','1990-01-22');

问题

SELECT emp_no , birth_date , first_name , last_name , gender , hire_date 
FROM employees 
ORDER BY hire_date DESC LIMIT 1

解决方案-02

SELECT emp_no , birth_date , first_name , last_name , gender , hire_date 
FROM employees 
WHERE hire_date = (SELECT max(hire_date) FROM employees) LIMIT 1
  1. 请你查找employees里入职员工时间排名倒数第三的员工所有信息
    解决方案-01
    这个方案的问题是如果遇到入职时间重复的问题:
SELECT * FROM employees ORDER  BY hire_date DESC LIMIT 2 , 1

解决方案-02
去除重复的入职时间

SELECT * FROM employees 
WHERE 
hire_date = 
(SELECT distinct hire_date FROM employees ORDER BY hire_date DESC LIMIT 2 , 1)

02 查找当前薪水详情以及部门编号dept_no

创建表

	DROP TABLE IF EXISTS `salaries`;
	CREATE TABLE `salaries` (
		`emp_no` int(11) NOT NULL COMMENT '员工编号',
		`salary` int(11) NOT NULL COMMENT '薪资' ,
		`from_date` date NOT NULL COMMENT '开始时间',
		`to_date` date NOT NULL COMMENT '到期时间',
	PRIMARY KEY (`emp_no`,`from_date`))
	COMMENT '工资表';
	
	INSERT INTO salaries (emp_no , salary ,from_date , to_date) 
	VALUES 
	(10001 , 88958 , '2002-06-22' , '9999-01-01'),
	(10002 , 72527 , '2001-08-02' , '9999-01-01'),
	(10003 , 43311 , '2001-12-01' , '9999-01-01')
	
	
	DROP TABLE IF EXISTS `dept_manager`;
	CREATE TABLE `dept_manager` (
		`dept_no` char(4) NOT NULL COMMENT '部门编号',
		`emp_no` int(11) NOT NULL COMMENT '员工编号',
		`to_date` date NOT NULL ,
	PRIMARY KEY (`emp_no`,`dept_no`))
	COMMENT '部门经理表';
	
	INSERT INTO dept_manager (dept_no , emp_no , to_date) 
	VALUES
	('d001' , 10001 , '9999-01-01'),
	('d002' , 10003 , '9999-01-01')

问题

  1. 请你查找各个部门当前领导的薪水详情以及其对应部门编号dept_no,输出结果以salaries.emp_no升序排序,并且请注意输出结果里面dept_no列是最后一列

方案-01

SELECT s.emp_no , s.salary , s.from_date , s.to_date,  d.dept_no FROM salaries as s 
INNER JOIN dept_manager as d ON s.emp_no = d.emp_no 
ORDER  BY s.emp_no ASC

方案-02

SELECT s.emp_no , s.salary , s.from_date , s.to_date,  d.dept_no FROM salaries as s 
INNER JOIN dept_manager as d ON s.emp_no = d.emp_no 
where s.to_date='9999-01-01' and d.to_date='9999-01-01'
ORDER  BY s.emp_no ASC

04 查找所有已经分配部门的员工的last_name和first_name以及dept_no

创建数据库表

	DROP TABLE IF EXISTS `dept_emp`;
	CREATE TABLE `dept_emp` (
	`emp_no` int(11) NOT NULL COMMENT '员工编号',
	`dept_no` char(4) NOT NULL COMMENT '部门编号',
	`from_date` date NOT NULL COMMENT '合同起始时间',
	`to_date` date NOT NULL COMMENT '合同终止时间',
	PRIMARY KEY (`emp_no`,`dept_no`))
	COMMENT '部门表';
	
	INSERT INTO dept_emp VALUES(10001,'d001','1986-06-26','9999-01-01');
	INSERT INTO dept_emp VALUES(10002,'d001','1996-08-03','9999-01-01');
	INSERT INTO dept_emp VALUES(10003,'d004','1995-12-03','9999-01-01');
	INSERT INTO dept_emp VALUES(10004,'d004','1986-12-01','9999-01-01');
	INSERT INTO dept_emp VALUES(10005,'d003','1989-09-12','9999-01-01');
	INSERT INTO dept_emp VALUES(10006,'d002','1990-08-05','9999-01-01');
	INSERT INTO dept_emp VALUES(10007,'d005','1989-02-10','9999-01-01');
	INSERT INTO dept_emp VALUES(10008,'d005','1998-03-11','9999-01-01');
	INSERT INTO dept_emp VALUES(10009,'d006','1985-02-18','9999-01-01');
	INSERT INTO dept_emp VALUES(10010,'d006','2000-06-26','9999-01-01');
	INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
	INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
	INSERT INTO employees VALUES(10003,'1959-12-03','Parto','Bamford','M','1986-08-28');
	INSERT INTO employees VALUES(10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01');
	INSERT INTO employees VALUES(10005,'1955-01-21','Kyoichi','Maliniak','M','1989-09-12');
	INSERT INTO employees VALUES(10006,'1953-04-20','Anneke','Preusig','F','1989-06-02');
	INSERT INTO employees VALUES(10007,'1957-05-23','Tzvetan','Zielinski','F','1989-02-10');
	INSERT INTO employees VALUES(10008,'1958-02-19','Saniya','Kalloufi','M','1994-09-15');
	INSERT INTO employees VALUES(10009,'1952-04-19','Sumant','Peac','F','1985-02-18');
	INSERT INTO employees VALUES(10010,'1963-06-01','Duangkaew','Piveteau','F','1989-08-24');
	INSERT INTO employees VALUES(10011,'1953-11-07','Mary','Sluis','F','1990-01-22');

问题

  1. 请你查找所有已经分配部门的员工的last_name和first_name以及dept_no,未分配的部门的员工不显示
SELECT DISTINCT e.last_name , e.first_name , d.dept_no FROM employees AS e 
INNER JOIN dept_emp AS d ON e.emp_no = d.emp_no 

05 查找所有员工的last_name和first_name以及对应部门编号dept_no

创建数据库表

同04题数据库表

问题

  1. 请你查找所有已经分配部门的员工的last_name和first_name以及dept_no,也包括暂时没有分配具体部门的员工

解决方案

SELECT DISTINCT e.last_name , e.first_name , d.dept_no FROM employees AS e 
LEFT JOIN dept_emp AS d ON e.emp_no = d.emp_no 

07 查找薪水记录超过15次的员工号emp_no以及其对应的记录次数t

创建表 同上

	DROP TABLE IF EXISTS `salaries`;
	CREATE TABLE `salaries` (
		`emp_no` int(11) NOT NULL COMMENT '员工编号',
		`salary` int(11) NOT NULL COMMENT '薪资' ,
		`from_date` date NOT NULL COMMENT '开始时间',
		`to_date` date NOT NULL COMMENT '到期时间',
	PRIMARY KEY (`emp_no`,`from_date`))
	COMMENT '工资表';
	
	INSERT INTO salaries VALUES(10001,60117,'1986-06-26','1987-06-26');
	INSERT INTO salaries VALUES(10001,62102,'1987-06-26','1988-06-25');
	INSERT INTO salaries VALUES(10001,66074,'1988-06-25','1989-06-25');
	INSERT INTO salaries VALUES(10001,66596,'1989-06-25','1990-06-25');
	INSERT INTO salaries VALUES(10001,66961,'1990-06-25','1991-06-25');
	INSERT INTO salaries VALUES(10001,71046,'1991-06-25','1992-06-24');
	INSERT INTO salaries VALUES(10001,74333,'1992-06-24','1993-06-24');
	INSERT INTO salaries VALUES(10001,75286,'1993-06-24','1994-06-24');
	INSERT INTO salaries VALUES(10001,75994,'1994-06-24','1995-06-24');
	INSERT INTO salaries VALUES(10001,76884,'1995-06-24','1996-06-23');
	INSERT INTO salaries VALUES(10001,80013,'1996-06-23','1997-06-23');
	INSERT INTO salaries VALUES(10001,81025,'1997-06-23','1998-06-23');
	INSERT INTO salaries VALUES(10001,81097,'1998-06-23','1999-06-23');
	INSERT INTO salaries VALUES(10001,84917,'1999-06-23','2000-06-22');
	INSERT INTO salaries VALUES(10001,85112,'2000-06-22','2001-06-22');
	INSERT INTO salaries VALUES(10001,85097,'2001-06-22','2002-06-22');
	INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
	INSERT INTO salaries VALUES(10002,72527,'1996-08-03','1997-08-03');

问题

  1. 请你查找薪水记录超过15次的员工号emp_no以及其对应的记录次数t

解决方案-01

错误点: group by 时,过滤条件用HAVING WHERE

SELECT emp_no, COUNT(DISTINCT from_date) AS t FROM salaries
GROUP BY emp_no
HAVING t > 15

08 找出所有员工当前薪水salary情况

创建数据库表

	drop table if exists  `salaries` ; 
	CREATE TABLE `salaries` (
	`emp_no` int(11) NOT NULL,
	`salary` int(11) NOT NULL,
	`from_date` date NOT NULL,
	`to_date` date NOT NULL,
	PRIMARY KEY (`emp_no`,`from_date`));	
	INSERT INTO salaries VALUES(10001,88958,'2002-06-22','9999-01-01');
	INSERT INTO salaries VALUES(10002,88958,'2002-06-22','9999-01-01');
	INSERT INTO salaries VALUES(10003,43311,'2001-12-01','9999-01-01');
	INSERT INTO salaries VALUES(10004,43311,'2001-12-01','9999-01-01');
	INSERT INTO salaries VALUES(10005,94692,'2001-09-09','9999-01-01');
	INSERT INTO salaries VALUES(10006,43311,'2001-08-02','9999-01-01');
	INSERT INTO salaries VALUES(10007,88070,'2002-02-07','9999-01-01');
	INSERT INTO salaries VALUES(10008,88070,'2002-02-07','9999-01-01');
	INSERT INTO salaries VALUES(10009,95409,'2002-02-14','9999-01-01');
	INSERT INTO salaries VALUES(10011,25828,'1990-01-22','9999-01-01');

问题

  1. 请你找出所有员工具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示

解决方案-01

	# 这里是创建索引试试,索引是个很好玩的东西
	# DROP INDEX salary ON salaries ;
	# CREATE INDEX salary ON salaries (salary) ;
	SELECT DISTINCT salary FROM salaries ORDER BY salary DESC ;
	# DROP INDEX salary ON salaries;

09 获取所有非manager的员工emp_no

创建表

drop table if exists  `dept_manager` ; 
		drop table if exists  `employees` ; 
		CREATE TABLE `dept_manager` (
		`dept_no` char(4) NOT NULL,
		`emp_no` int(11) NOT NULL,
		`from_date` date NOT NULL,
		`to_date` date NOT NULL,
		PRIMARY KEY (`emp_no`,`dept_no`));
		
		CREATE TABLE `employees` (
		`emp_no` int(11) NOT NULL,
		`birth_date` date NOT NULL,
		`first_name` varchar(14) NOT NULL,
		`last_name` varchar(16) NOT NULL,
		`gender` char(1) NOT NULL,
		`hire_date` date NOT NULL,
		PRIMARY KEY (`emp_no`));
		INSERT INTO dept_manager VALUES('d001',10002,'1996-08-03','9999-01-01');
		INSERT INTO dept_manager VALUES('d002',10003,'1990-08-05','9999-01-01');
		INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
		INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
		INSERT INTO employees VALUES(10003,'1959-12-03','Parto','Bamford','M','1986-08-28');

问题

  1. 请你找出所有非部门领导的员工emp_no

解决方案-01

SELECT  e.emp_no FROM employees AS e 
LEFT JOIN dept_manager as d ON e.emp_no = d.emp_no 
WHERE d.emp_no is NULL

10 获取所有员工当前的manager

创建表

drop table if exists  `dept_emp` ; 
		drop table if exists  `dept_manager` ; 
		CREATE TABLE `dept_emp` (
		`emp_no` int(11) NOT NULL,
		`dept_no` char(4) NOT NULL,
		`from_date` date NOT NULL,
		`to_date` date NOT NULL,
		PRIMARY KEY (`emp_no`,`dept_no`));
		
		CREATE TABLE `dept_manager` (
		`dept_no` char(4) NOT NULL,
		`emp_no` int(11) NOT NULL,
		`from_date` date NOT NULL,
		`to_date` date NOT NULL,
		PRIMARY KEY (`emp_no`,`dept_no`));
		
		INSERT INTO dept_emp VALUES(10001,'d001','1986-06-26','9999-01-01');
		INSERT INTO dept_emp VALUES(10002,'d001','1996-08-03','9999-01-01');
		INSERT INTO dept_emp VALUES(10003,'d002','1995-12-03','9999-01-01');
		INSERT INTO dept_manager VALUES('d001',10002,'1996-08-03','9999-01-01');
		INSERT INTO dept_manager VALUES('d002',10003,'1990-08-05','9999-01-01');

11. 问题

  1. 获取所有的员工和员工对应的经理,如果员工本身是经理的话则不显示

解决方案-O1

有两个语法问题:
1. 在 sql_mode=only_full_group_by 时,GROUP BY 后面要加上select后的所有字段
2. DISTINCT 的时候,如果查询多个字段,DISTINCT 后的字段要放在select 后的第一个字段

SELECT  e.emp_no AS emp_no , m.emp_no AS manager  FROM dept_emp AS e 
INNER JOIN dept_manager AS m ON e.dept_no = m.dept_no 
WHERE e.emp_no != m.emp_no
GROUP BY e.emp_no , m.emp_no

12

创建表

	drop table if exists  `dept_emp` ; 
	drop table if exists  `salaries` ; 
	CREATE TABLE `dept_emp` (
	`emp_no` int(11) NOT NULL,
	`dept_no` char(4) NOT NULL,
	`from_date` date NOT NULL,
	`to_date` date NOT NULL,
	PRIMARY KEY (`emp_no`,`dept_no`));
	CREATE TABLE `salaries` (
	`emp_no` int(11) NOT NULL,
	`salary` int(11) NOT NULL,
	`from_date` date NOT NULL,
	`to_date` date NOT NULL,
	PRIMARY KEY (`emp_no`,`from_date`));
	INSERT INTO salaries VALUES (10001, 90000, '1986-06-26', '1987-06-26');
	INSERT INTO salaries VALUES (10001, 95000, '2002-06-22', '9999-01-01');
	INSERT INTO salaries VALUES (10002, 72527, '1996-08-03', '1997-08-03');
	INSERT INTO salaries VALUES (10002, 72527, '2000-08-02', '2001-08-02');
	INSERT INTO salaries VALUES (10002, 95000, '2001-08-02', '9999-01-01');
	INSERT INTO salaries VALUES (10003, 90000, '1996-08-03', '1997-08-03');
	INSERT INTO salaries VALUES (10004, 80000, '1996-01-01', '1996-03-01');
	INSERT INTO salaries VALUES (10004, 89000, '1996-08-08', '9999-01-01');

	INSERT INTO dept_emp VALUES (10001, 'd001', '1986-06-26', '9999-01-01');
	INSERT INTO dept_emp VALUES (10002, 'd001', '1996-08-03', '9999-01-01');
	INSERT INTO dept_emp VALUES (10003, 'd001', '1996-08-03', '1997-08-03');
	INSERT INTO dept_emp VALUES (10004, 'd002', '1996-08-08', '9999-01-01');

问题

1. 获取每个部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门编号升序排列,

解决方案-01

要充分使用join来进行联合表示
select de.dept_no, emp_no, max_salary FROM dept_emp de
	join
	(
		select dept_no, max(salary) as max_salary FROM salaries s
		join dept_emp de on s.emp_no = de.emp_no
		where s.to_date = '9999-01-01' and de.to_date = '9999-01-01'
		group by dept_no
	)  t on de.dept_no = t.dept_no where de.to_date = '9999-01-01'
	
	SELECT * from  salaries
	WHERE salary = 
	(
		SELECT MAX(max_salary) from 
			(
				select dept_no, max(salary) as max_salary FROM salaries s
				INNER join dept_emp de on s.emp_no = de.emp_no
				where s.to_date = '9999-01-01' and de.to_date = '9999-01-01'
				group by dept_no
			) AS t
	)

13 查找employees表

创建表

	drop table if exists  `employees` ; 
	CREATE TABLE `employees` (
	`emp_no` int(11) NOT NULL,
	`birth_date` date NOT NULL,
	`first_name` varchar(14) NOT NULL,
	`last_name` varchar(16) NOT NULL,
	`gender` char(1) NOT NULL,
	`hire_date` date NOT NULL,
	PRIMARY KEY (`emp_no`));
	INSERT INTO employees VALUES(10001,'1953-09-02','Georgi','Facello','M','1986-06-26');
	INSERT INTO employees VALUES(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21');
	INSERT INTO employees VALUES(10003,'1959-12-03','Bezalel','Mary','M','1986-08-28');
	INSERT INTO employees VALUES(10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01');
	INSERT INTO employees VALUES(10005,'1953-11-07','Mary','Sluis','F','1990-01-22');

问题

1. 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列

解决方案-01

遇到GROUP BY问题,用下面set解决,出现sql_mode = only_full_xx的问题 , 执行下面命令,重新连接就可以了
set @@global.sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
# 解决方案,这里判断奇偶用的位运算, 尽量不要用!= , 用not exits 不用not in
SELECT * FROM employees AS e  WHERE e.emp_no & 1 = 1 AND e.last_name <> 'Mary'
ORDER BY hire_date DESC

总结

一共有80到sql题,会在一定时间内做完
现在ORM框架的简便性,慢慢弱化sql能力,我个人觉得sql能力还是很重要的
而且sql能力在面试中也占了很大的分量,所以在牛客网上找点联系题做。

小经验:
关于测试用例问题,在牛客网在线编辑器中,可以设置为联系模式,然后输入一段能编译过但运行失败的sql,然后就可以拷贝出创建数据库语句和测试数据sql语句。免得自己一个一个敲,这个弊端就是,降低自己的提交通过率,不过这也没啥,真正学到东西才是真的,通过率哪些不在意。

注意:
关于题号不连续问题,有的题可以合并成一个题,我就合并了,但是题号按照牛客网题号来的。

答案不是最佳解决方案 ,但是一定是通过测试用例的方案,此篇文章属于长期完成,做完一轮后我会再进行sql优化
之前看到一篇文章,学习一开始不要太较真,不要一下子扎进某个点深入,要先了解整体,造一辆车要先把车造出来,能跑起来再说。跑起来了在考虑优化发动机来提升动力

Top