1、牛客网网址mysql
https://www.nowcoder.com/ta/sql,一共76道真题。sql
PS:不要过于相信在线编译器!!!作完每一题要记得看各位网友大神解读和总结。express
2、题目函数
一、查找最晚入职员工的全部信息,为了减轻入门难度,目前全部的数据里员工入职的日期都不是同一天(sqlite里面的注释为--,mysql为comment)
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`));性能
解题:spa
(1)假设员工入职的日期都不是同一天,日期降序排序后,直接截取第一条数据便可。code
select * from employees order by hire_date desc limit 1;
limit m,n:m为起始索引位置(索引从0开始),日后获取n行数据。如limit 6,10 获取第7行到16行数据。另外一种写法:limit n offset msqlite
limit 语句运行顺序排到最后,由于它是从结果集中截取部分行数。blog
(2)假设员工入职的日期有可能同一天。排序
select * from employees where hire_date = ( select max(hire_date) from employees); #1.用子查询获取最迟入职日期; #2.把入职日期等于最迟入职日期的全部全找出来。
二、查找入职员工时间排名倒数第三的员工全部信息,为了减轻入门难度,目前全部的数据里员工入职的日期都不是同一天
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`));
解题:
(1)假设员工入职的日期都不是同一天
select * from employees order by hire_date desc limit 2,1; # 直接降序排序获取第三行记录便可
(2)假设员工入职的日期有可能同一天
select * from employees where hire_date=( select distinct hire_date from employees order by hire_date desc limit 1 offset 2 ); #1.先用distinct把重复的日期去重,获得的日期都是惟一的 #2.再排序后,用limit获取倒数第三天入职的日期 #3.最后把入职日期等于倒数第三天日期的员工信息所有获取
三、
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL, -- '部门编号'
`emp_no` int(11) NOT NULL, -- '员工编号'
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
解题:
select sa.*, dm.dept_no from salaries as sa inner join dept_manager as dm on dm.emp_no = sa.emp_no where sa.to_date='9999-01-01' and dm.to_date='9999-01-01' order by sa.emp_no asc; # 考察表的内链接和一些实际状况业务的了解
四、查找全部已经分配部门的员工的last_name和first_name以及dept_no(请注意输出描述里各个列的先后顺序)
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 `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`));
解题:
select last_name, first_name, dept_no from employees e inner join dept_emp d on e.emp_no = d.emp_no where dept_no is not null; # 考察表内链接,不用指定dept_no是否为null,由于内链接中,任何一边有缺失数据就不会显示。
五、查找全部员工的last_name和first_name以及对应部门编号dept_no,也包括暂时没有分配具体部门的员工(请注意输出描述里各个列的先后顺序)
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 `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`));
select last_name,first_name,dept_no from employees e left join dept_emp d on e.emp_no = d.emp_no; #即便没有分配部门的员工也要显示,意味着employees表中全部emp_no都要显示,无论dept_emp表的对应dept_no是否缺失。考察左链接
多表链接查询知识点总结:
表1 inner join 表2 两边表同时有对应的数据,即任何一边有缺失数据就不显示;
主 left join 从 左边主表的数据所有读取,右边从边无对应数据的填充NULL值;
从 right join 主 反之;
六、查找全部员工入职时候的薪水状况,给出emp_no以及salary, 并按照emp_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`));
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`));
解题:
(1)表链接
select e.emp_no, s.salary from employees e inner join salaries s on e.emp_no = s.emp_no where s.from_date = e.hire_date order by e.emp_no desc; # 1.有涨薪或者降薪,说明salaries表中的每个emp_no至少有一个,薪水变过就有重复值。 # 2.只要from_date等于入职日期hire_date,薪水就是入职时的薪水。
(2)分组以后求日期最小值
select emp_no,salary from salaries group by emp_no having min(from_date) order by emp_no desc; # 1.先用emp_no分组,获得每一个员工分组数据 # 2.再用having对每一个分组求最先日期,即刚入职的日期,不能求最小工资,由于员工有可能被降薪。 # 3.数据量大时,不建议用分组查询,由于having以后,程序会在每一个分组表中在遍历一遍,可能致使性能不佳。
七、查找薪水变更超过15次的员工号emp_no以及其对应的变更次数t
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`));
解题:
select emp_no,count(*) as t from salaries group by emp_no having count(*) > 15; # 考察点是分组统计查询,
分组聚合筛选查询知识点概括:
语法:
SELECT column1, column2, ... column_n, aggregate_function (expression),constant
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n
HAVING condition1 ... condition_n;
重点:
(12题,有典型的错误例子。)
八、找出全部员工当前(to_date='9999-01-01')具体的薪水salary状况,对于相同的薪水只显示一次,并按照逆序显示
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`));
解题:
(1)distinct关键字排除重复
select distinct salary from salaries where to_date='9999-01-01' order by salary desc; # distinct 多列去重时,只有全部列的信息彻底一致才认为时重复的。
(2)用group by去重,听说数据量很大时,效率比较高
select salary from salaries where to_date='9999-01-01' group by salary order by salary desc;
九、获取全部部门当前(dept_manager.to_date='9999-01-01')manager的当前(salaries.to_date='9999-01-01')薪水状况,给出dept_no, emp_no以及salary(请注意,同一我的可能有多条薪水状况记录)
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 `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`));
解题:
select dept_no,d.emp_no,salary from dept_manager d inner join salaries s on d.emp_no = s.emp_no where d.to_date='9999-01-01' and s.to_date='9999-01-01';
十、获取全部非manager的员工emp_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`));
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,
select e.emp_no from employees e left join dept_manager d on e.emp_no = d.emp_no where d.dept_no is null; # 1.假如员工不是manager,那么dept_no字段应该为null # 2.经过左链接的方式,使不是manager的dept_no字段为null,再筛选便可
(2)子查询
select emp_no from employees where emp_no not in( select d.emp_no from dept_manager d inner join employees e on d.emp_no = e.emp_no ); # 1.先用子查询查出是manger的emp_no # 2.再判断员工emp_no不在manger的emp_no里面便可 # 3.子查询能够直接用select emp_no from dept_manager,毕竟dept_manager这个表存的是manage的信息。
十一、获取全部员工当前的(dept_manager.to_date='9999-01-01')manager,若是员工是manager的话不显示(也就是若是当前的manager是本身的话结果不显示)。输出结果第一列给出当前员工的emp_no,第二列给出其manager对应的emp_no。
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,
select de.emp_no, dm.emp_no as manager_no from dept_emp de inner join dept_manager dm on dm.dept_no = de.dept_no where de.emp_no <> dm.emp_no and dm.to_date='9999-01-01' and de.to_date='9999-01-01'; # 1.两表内链接后,只有manager的de.emp_no和dm.emp_no是同样的,用where筛选掉便可。 # 2.由于部门的manager有可能会离职或者更换,要保证manage和普通员工都在同一时间在同一部门才能构成从属关系。两个跨时空的人恋爱会很惨的!!!
十二、获取全部部门中当前(dept_emp.to_date = '9999-01-01')员工当前(salaries.to_date='9999-01-01')薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门升序排列。
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,