美文网首页
牛客sql刷题记录(更新中)

牛客sql刷题记录(更新中)

作者: 美琦miki视觉笔记 | 来源:发表于2020-04-15 20:21 被阅读0次

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

    方法一:

    select * from employees
    order by hire_date desc
    limit 0,1
    

    LIMIT m,n : 表示从第m+1条开始,取n条数据;
    LIMIT n : 表示从第0条开始,取n条数据,是limit(0,n)的缩写。
    本题limit 0,1 表示从第(0+1)条数据开始,取一条数据,即取出最晚入职员工。

    方法二,更周到,因为最晚入职会不止一条。可能时间日期是一样的。

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

    2.查找入职员工时间排名倒数第三的员工所有信息

    嗯如果是接着上一个题目的修正版本:

    select * from employees
    order by hire_date desc
    limit 2,1
    

    很简单就过了。但是其实是有歧义的。
    不过如果要去重啥的好像要复杂一些
    以及用row_number之类怎么定义这个倒数第三,先不管他了。

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

    select b.*,a.dept_no
    from salaries b
    inner join dept_manager a
    on a.emp_no=b.emp_no
    where a.to_date='9999-01-01'
    and b.to_date='9999-01-01'
    

    2个易错点:两个to_date都要限制,防止数据错误
    主表salary放在前面,salary 和dept表的顺序换掉会跑不过,但我倒是不觉得有啥问题?

    另外where改成and 连在on后面也能过

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

    select 
    a.last_name,a.first_name,b.dept_no
    from employees a 
    inner join dept_emp b
    on a.emp_no=b.emp_no
    

    简单题

    5.查找所有员工的last_name和first_name以及对应部门编号dept_no,也包括展示没有分配具体部门的员工

    select 
    a.last_name,a.first_name,b.dept_no
    from employees a 
    left join dept_emp b
    on a.emp_no=b.emp_no
    

    在4的基础上改成left就好

    6.查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序

    select  a.emp_no,b.salary
    from employees a
    inner join salaries b
    on a.emp_no=b.emp_no
    and a.hire_date=b.from_date
    order by a.emp_no desc
    

    入职时候的薪水情况 所以有个 a.hire_date=b.from_date
    话说写 and 和where应该都行吧,on and效率高一点,这个可以再查一下。但据说实习的时候能写on就不写where了。

    7.查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t

    select emp_no,count(distinct salary)-1 as t
    from salaries
    group by emp_no
    having count(distinct salary)>15
    

    比较合理的话应该是这样,不过通不过,这题目里不是算差值,有一条就算涨幅了。。emm 改成这样就通过了。
    然后涨幅也不要管是不是比上一次怎样了,就算count就好了。这题是这样。

    select emp_no,count(distinct salary) as t
    from salaries
    group by emp_no
    having count(distinct salary)>=15
    

    8.找出所有员工当前(to_date='9999-01-01')具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示

    select distinct salary 
    from salaries
    where to_date='9999-01-01'
    order by salary desc
    

    楼上都是用distinct,但是大表一般用distinct效率不高,大数据量的时候都禁止用distinct,建议用group by解决重复问题。
    对于distinct与group by的使用: 1、当对系统的性能高并数据量大时使用group by 2、当对系统的性能不高时使用数据量少时两者皆可 3、尽量使用group by

    select salary 
    from salaries
    where to_date='9999-01-01'
    group by salary
    order by salary desc
    

    9.获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date='9999-01-01'

    select a.dept_no,a.emp_no,b.salary
    from dept_manager a
    left join salaries b
    on a.emp_no=b.emp_no
    where a.'to_date'='9999-01-01'
    and b.'to_date'='9999-01-01'
    

    left改成inner也可以通过,不过现实工作中,有的领导没有工资应该填写null去排查。

    10.获取所有非manager的员工emp_no

    select a.emp_no
    from employees a
    left join  dept_manager b
    on a.emp_no=b.emp_no
    where  b.emp_no is null
    

    11.获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。

    结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。

    select a.emp_no as emp_no,b.emp_no as manager_no
    from dept_emp a
    left join dept_manager b
    on a.dept_no=b.dept_no
    where a.to_date='9999-01-01'
    and b.to_date='9999-01-01'
    and a.emp_no <> b.emp_no
    

    容易错的 一个是命名
    一个是最后一句如果当前的manager是自己的话结果不显示
    这里的不显示是指当部门主管是自己的时候,整行都不显示;不是不显示部门经理的编号。
    这道题用INNER JOIN 和 LEFT JOIN 是都可以通过的,因为默认职员表中每个职员都是分配了部门的,因此保留不保留职员表(左表)没有关联的行(实际上都关联了)结果都一样

    另外一个不错的关于on和where 的解释

    通不过:

    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 de.to_date = '9999-01-01' AND dm.to_date = '9999-01-01' 
    AND de.emp_no NOT IN (SELECT dm.emp_no FROM dept_manager)  - 这里的and改成where可以通过,因为用on的话经理也会显示,只是显示null,这里的不显示是指当部门主管是自己的时候,整行都不显示,所以要过滤掉
    

    通过了:

    SELECT de.emp_no, dm.emp_no AS manager_no
    FROM dept_emp AS de
    INNER JOIN dept_manager AS dm
    ON de.dept_no = dm.dept_no
    AND de.to_date = '9999-01-01' AND dm.to_date = '9999-01-01'
    AND de.emp_no NOT IN (SELECT dm.emp_no FROM dept_manager)
    

    这里涉及ON和WHERE的用法。

    使用连接操作,关联两张或多张表时,数据库会生成并返回一张临时表。

    LEFT JOIN 模式下,ON 和 WHERE 过滤条件的区别( RIGHT JOIN、FULL JOIN 同理):
    ON 条件是在生成临时表时使用的条件,不管 ON 中的条件是否为真,都会返回左边表中的记录;
    WHERE 条件是在临时表已经生成后,对临时表进行的过滤条件,如果 WHERE 条件不为真,记录就会被过滤掉。

    INNER JOIN 只返回同时存在于两张或多张表的行数据,所以过滤条件放在 ON 中或 WHERE 中,返回的结果一样。

    12.获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary

    能通过但是有问题:
    问题在于emp_no
    同时select了b.dept_no,a.emp_no,但是group by 第一个b.dept_no
    那会出现一个部门有多条emp_no,但最后筛选出来的是默认第一条, 而非max对应的那一条。

    这个问题其实也包括了我曾经困扰的:
    select 多字段 ,但是只group by 其中某些字段
    有时候会出错的, 因为都会出现默认第一条。
    有些时候我们可以用max或者sum来筛选。

    select b.dept_no,a.emp_no,max(a.salary) as salary
    from salaries a
    inner join dept_emp b
    on a.emp_no=b.emp_no
    
    where a.to_date='9999-01-01'
    and b.to_date='9999-01-01'
    group by 1
    

    修改成,三表匹配:

    select c.dept_no,d.emp_no,c.max_salary
    from
        (select b.dept_no,max(a.salary) as max_salary
        from salaries a
        inner join dept_emp b
        on a.emp_no=b.emp_no
        where a.to_date='9999-01-01'
        and b.to_date='9999-01-01'
        group by 1)c
    inner join salaries d
    on c.max_salary=d.salary
    inner join dept_emp e
    on d.emp_no=e.emp_no
    and c.dept_no=e.dept_no
    where d.to_date='9999-01-01'
    and e.to_date='9999-01-01'
    order by c.dept_no asc
    

    另外一个更常用,不容易出错的方法,就是窗口函数

    select c.dept_no,c.emp_no,c.salary
    from
        (select a.dept_no,b.emp_no,b.salary,
        rank() over(partition by a.dept_no order by b.salary desc) as ranking
        from dept_emp a
        inner join salaries b
        on a.emp_no=b.emp_no
        where a.to_date='9999-01-01' and b.to_date='9999-01-01'
        )c
    
    where c.ranking=1
    
    

    13.从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。

    so easy

    select title,count(*) as t
    from titles
    group by 1
    having count(*)>=2
    

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

    我是这样写的,不过看了大家的讨论有一些争议。
    争议在于有人说distinct是对后面所有的起作用的。

    select title,count(*) as t
    from 
    (select distinct emp_no,title from titles)
    group by 1
    having count(*)>=2
    

    答案是

    select  title ,count(distinct emp_no) as t
    from titles 
     
    group by title 
    having t >= 2
    

    distinct 与group by 去重

    mysql中常用去重复数据的方法是使用 distinct 或者group by ,以上2种均能实现,但2者也有不同的地方。

    distinct 特点:

    如:select distinct name, sex,from tb_students 这个sql的语法中,查询 tb_students 表中 name, sex,并去除名字和性别都重复的学生:

    1、distinct 只能放在查询字段的最前面,不能放在查询字段的中间或者后面。

    备注:select sex,distinct name from tb_students 这种写法是错误的,distinct 只能写在所有查询字段的前面

    2、distinct 对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 distinct 后面连接的单个字段重复的数据。

    备注:也就是 distinct 关键字对 name, sex 都起作用,去重姓名、性别完全一样的学生,如果姓名相同、性别不同是不会去重的。

    3、要查询多个字段,但只针对一个字段去重,使用distinct去重的话是无法实现的。

    group by 特点:

    1、一般与聚类函数使用(如count()/sum()等),也可单独使用。

    2、group by 也对后面所有的字段均起作用,即 去重是查询的所有字段完全重复的数据,而不是只对 group by后面连接的单个字段重复的数据。

    3、查询的字段与group by 后面分组的字段没有限制。

    特别说明:在oracle中使用group by时,查询的字段必须是group by 分组的字段和聚类函数。如select name,sex from tb_students group by name这个sql

    语法在oracle中是错误的,因为sex 不在group by 分组后面;但在mysql中是支持的。

    14.查找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
    

    mod(emp_no,2)=1本应该也可以。但是可能牛客的库不支持。

    15.统计出当前各个title类型对应的员工当前(to_date='9999-01-01')薪水对应的平均工资。结果给出title以及平均工资avg。

    select b.title,avg(a.salary)
    from salaries a inner join
    titles b
    on a.emp_no=b.emp_no
    where a.to_date='9999-01-01'
    and b.to_date='9999-01-01'
    group by 1
    

    16.获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水salary

    select  a.emp_no,a.salary 
    from
    
    (select emp_no,salary,
        dense_rank()over (order by salary desc)as ranking
    from salaries)a
    where a.ranking=2
    

    dense_rank 是11112的类型。

    相关文章

      网友评论

          本文标题:牛客sql刷题记录(更新中)

          本文链接:https://www.haomeiwen.com/subject/fpvhvhtx.html