牛客网:数据库SQL实战题库笔记

牛客网原题地址


牛客网的测试系统是SQLite,所以有一些用法与MySQL不一致

1. 查找最晚入职员工的所有信息
select * from employees order by hire_date desc limit 0,1

方法1:若最晚入职员工只有1人,则按入职时间倒序排列,排在第一的就是目标人员。

select * from employees 
where hire_date=(select max(hire_date) from employees)

方法2:若最晚入职员工不止1人,则先查出最晚的入职日期,再用此日期作为筛选条件。


2. 查找入职员工时间排名倒数第三的员工所有信息
select * from employees order by hire_date desc limit 2,1

此题考查order by和limit用法:

  • “入职时间排名倒数”,使用order by hire_date desc
  • “第三名”,位置排在3,且为1人,使用limit 2,1。排序从0开始,若此题改为“第一名”,则用limit 0,1(此处0可省略)。

3. 查找各个部门当前(to_date=‘9999-01-01’)领导当前薪水详情以及其对应部门编号dept_no

感觉题目有点问题:增加一句“输出结果按emp_no递增排序”就没异议了。
题干中的“输出描述”已经暗含了此排序,输出结果必须与之完全一致才能通过(这确实有些不合理)。

解法1:salaries作为主表,salaries的主键是emp_no,结果按emp_no递增排序

select s.* ,d.dept_no from salaries as s 
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'

解法2:dept_manager作为主表,dept_manager的主键是dept_no,结果按dept_no递增排序

select s.* ,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  #比解法1多了一步按emp_no递增排序
  • 表salaries里,1个人可能会发多次工资,对应多个to_date,因此用s.to_date = '9999-01-01’筛选“当前薪水”。
  • 表dept_manager里,1个部门可能有过多个领导,对应多个to_date,因此用d.to_date = '9999-01-01’筛选“部门当前领导”。

4. 查找所有已经分配部门的员工的last_name和first_name以及dept_no
select e.last_name,e.first_name,d.dept_no 
from dept_emp as d
join employees as e on d.emp_no=e.emp_no
where dept_no is not null;
  • “已经分配部门的员工”,所以dept_no不能为空

5. 查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工
select 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
  • 与题目4的差别:“包括展示没有分配具体部门的员工”,不用排除dept_no为空的情况。

6. 查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序
select e.emp_no,s.salary
from employees as e
left join salaries as s
on e.emp_no=s.emp_no 
and e.hire_date=s.from_date
order by e.emp_no desc
  • “入职时候的薪水”,即发薪的from_date等于入职日期,employees.hire_date=salaries.from_date

7. 查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
select emp_no,count(emp_no) as t 
from salaries group by emp_no having t > 15

虽然本题通过了,但严格来讲不够严谨。本题每出现一次工资就认为涨幅1次,但可能不变,也可能降薪。


8. 找出所有员工当前(to_date=‘9999-01-01’)具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
select distinct salary from salaries 
where to_date='9999-01-01' 
group by emp_no 
order by salary desc
  • “当前”,to_date=‘9999-01-01’;
  • “相同的薪水只展现一次”,用distinct salary去重;
  • 同1个员工有多次发薪资的记录,因此需要去重group by emp_no,不过- 此题不用此步结果也正确,说明数据没有此情况;
  • “逆序”,order by salary desc。

9. 获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date=‘9999-01-01’
select d.dept_no,s.emp_no,s.salary
from salaries as s
left join dept_manager as d
on s.emp_no=d.emp_no
where d.to_date='9999-01-01'
and s.to_date='9999-01-01'

同题目3


10. 获取所有非manager的员工emp_no
select emp_no from employees
where emp_no not in 
(
    select emp_no from dept_manager
)
  • dept_manager中的emp_no都是manager
  • 从employees过滤掉dept_manager中的emp_no

11. 获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date=‘9999-01-01’。结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。
select de.emp_no,dm.emp_no as manager_no
from dept_emp as de
left join dept_manager as dm
on de.dept_no=dm.dept_no 
and dm.to_date='9999-01-01'
where de.emp_no <> dm.emp_no
  • “当前manager”,dm.to_date=‘9999-01-01’
  • “manager是自己的话结果不显示”,de.emp_no <> dm.emp_no

12. 获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary
select d.dept_no,d.emp_no,max(salary)
from dept_emp as d
left join salaries as s
on d.emp_no=s.emp_no
where d.to_date='9999-01-01'
group by d.dept_no
  • “当前员工”,d.to_date=‘9999-01-01’
  • “部门最高薪水”,先用group by d.dept_no按部门分组,再用max(salary)找出各部门最高薪水

13. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
select title,count(*) as t from titles
group by title
having t>=2
  • “按照title进行分组”,group by title
  • “每组个数大于等于2”,having t>=2

14. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。注意对于重复的emp_no进行忽略。

解法1:

  • 先创建一个包含title和不重复emp_no的临时表,select distinct emp_no,title from titles
  • 再对临时表进行分组和筛选,group by title, having t>=2
select title,count(1) as t from
(select distinct emp_no,title from titles) 
group by title
having t>=2

解法2:

  • 基于title分组,group by title
  • “每组个数大于等于2”,having t>=2
  • “忽略重复的emp_no”,count(distinct emp_no)
select title,count(distinct emp_no) as t from titles
group by title 
having t>=2
15. 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
select * from employees
where emp_no % 2 = 1
and last_name <> "Mary"
order by  hire_date desc
  • “奇数”,余数=1,emp_no %2 = 1
  • “last_name不为Mary”,last_name <> “Mary”
  • 逆序,order by desc
延展思考:判断奇数偶数常用办法

1.位运算:位运算符是在二进制数上进行计算的运算符。位运算会先将操作数变成二进制数,进行位运算。然后再将计算结果从二进制数变回十进制数。

  • 按位与
    位运算是对数的二进制进行的运算,利用按位与操作,就是 & 。奇数的二进制数的最后一位永远是 1,与 1 按位且只会得到 1,偶数相反。
select * from table where id&1 #筛选奇数
  • 右移1和左移1
    右移1(>>1)相当于十进制除以2,左移1(<<1)相当于十进制乘以2,先乘2再除2,若与原数相等则是偶数,不等是奇数。
select * from table where id<>(id>>1)<<1 #筛选奇数
select * from table where id=(id>>1)<<1 #筛选偶数

2. id计算

  • 求余数:%2或MOD(id,2),除以2余数是1则为奇数,余数是0则为偶数
select * from table where id%2=1 #筛选奇数
select * from table where id%2=0 #筛选偶数
select * from table where mod(id,2)=1 #筛选奇数
select * from table where mod(id,2)=0 #筛选偶数
  • -1的奇数次方和偶数次方
select * from table where power(-1,id)=-1 #筛选奇数
select * from table where power(-1,id)=1 #筛选偶数

16. 统计出当前各个title类型对应的员工当前(to_date=‘9999-01-01’)薪水对应的平均工资。结果给出title以及平均工资avg。
select title
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值