【SQL】牛客刷题笔记:SQL246~SQL254

1.SQL 246 获取employees的first_name

请你将employees中的first_name,并按照first_name最后两个字母升序进行输出。

【SQL】牛客刷题笔记:SQL246~SQL254_第1张图片

该题与SQL213、SQL226、SQL244类似,都考察了字符串相关的函数。本题所考察的函数是字符串截取函数substr(str,index,len)。该函数用法如下:

subtring(字符串,截取的起始位置,截取的字符数)

index从1开始,第三个参数可以省略,表示截取到最后一位

 本题中要求从从末尾截取,从后往前数使用负数表示。

select first_name
from employees 
order by substr(first_name,-2)

2.SQL 247 按照dept_no进行汇总

按照dept_no进行汇总,属于同一个部门的emp_no按照逗号进行连接,结果给出dept_no以及连接出的结果employees。

【SQL】牛客刷题笔记:SQL246~SQL254_第2张图片

改题目仍旧属于对字符串函数的考察 ,这里使用的函数是group_concat()。该函数可以字段进行连接,并按照排序字段的顺序用分隔符隔开。具体用法如下:

group_concat([distinct] 字段 [order by 排序字段 asc/desc]  separator  '分隔符')

separator字段也可以省略,省略则代表使用默认分隔符”,” 

select dept_no,group_concat(emp_no) as employees
from dept_emp
group by dept_no

3.SQL  248 平均工资

查找排除在职(to_date = '9999-01-01' )员工的最大、最小salary之后,其他的在职员工的平均工资avg_salary。

【SQL】牛客刷题笔记:SQL246~SQL254_第3张图片

本题需要求平均工资,但限定了员工范围为在职员工(to_date = '9999-01-01'),且不考虑最大值和最小值。

在职员工这个限定条件可以通过where子句根据to_date的值进行筛选,去除不符合条件的。同样,最大值和最小值也可以通过not in 关键字排除,注意因为工资最高或最低的员工可能不止一名,存在工资数相同的情况,因此不能用!=筛选。

本题考察的函数主要是max()和min()函数,这两个函数比较简单,不过多介绍。

select avg(salary) 
from salaries
where to_date = "9999-01-01"
and salary not in (select max(salary) from salaries where to_date  = "9999-01-01")
and salary not in  (select min(salary) from salaries where to_date ="9999-01-01")

4.SQL 249 分页查询employees表,每5行一页,返回第2页的数据

【SQL】牛客刷题笔记:SQL246~SQL254_第4张图片

 本题考查分页查询,分页查询也是在业务场景中经常遇到的情况,使用limit()函数即可解决。

  limit  x, y: x:表示偏移量(从0开始), y:表示获取的数据数量

计算分页的公式:limit (页数-1)*每页显示行数,每页显示行数

select * from employees limit 5,5

5.SQL 251 使用exists关键字查找未分配具体部门的员工

使用含有关键字exists查找未分配具体部门的员工的所有信息。

【SQL】牛客刷题笔记:SQL246~SQL254_第5张图片

 本题的常规解答是使用in关键字判断是否存在:

SELECT * FROM employees WHERE emp_no NOT IN (SELECT emp_no FROM dept_emp);

但本题中限定了需要使用exists关键字。exists的原理是:

exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当 exists里的条件语句能够返回记录行时,条件就为真,返回当前loop到的这条记录;反之如果exists里的条件语句不能返回记录行,则当前loop到的这条记录被丢弃。

也就是说,在 employees中挑选出exists条件不成立的记录。

select employees.*
from employees
where not exists (
    select emp_no
    from dept_emp
    where emp_no = employees.emp_no
)

补充:什么时候用EXISTS,什么时候用IN?
            当主表比从表大时,IN查询的效率较高;
            当从表比主表大时,EXISTS查询的效率较高;

6.SQL 253 获取有奖金的员工相关信息

bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%。 to_date='9999-01-01'表示当前薪水。

请你给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。

bonus结果保留一位小数,输出结果按emp_no升序排序。

【SQL】牛客刷题笔记:SQL246~SQL254_第6张图片

本题的难点在于多表连接,以及对奖金金额的计算。需要注意的是对薪水的查询限定了是当前的薪水情况( to_date='9999-01-01')。

多表链接比较简单,外连接就可以:

select e.emp_no ,first_name,last_name,b.btype,s.salary   
from employees e
join salaries s
using(emp_no)
join emp_bonus b
using(emp_no)
where s.to_date ="9999-01-01"

 比较麻烦的是对于奖金的计算,btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%,也就是要根据bytpe的值,要分情况讨论,也就是case when。

CASE

                WHEN condition THEN result

                [WHEN...THEN...]

                ELSE result

 END

 condition是一个返回布尔类型的表达式,如果返回true,则整个函数返回相应result的值,如果表达式均为false,则返回ElSE result的值,若ELSE子句省略,则返回NULL。

select e.emp_no ,first_name,last_name,b.btype,s.salary,round((
    case btype
    when 1 then (s.salary )*0.1
    when 2 then (s.salary) *0.2
    else (s.salary) *0.3
    end
),1) as bonus
from employees e
join salaries s
using(emp_no)
join emp_bonus b
using(emp_no)
where s.to_date ="9999-01-01"

这里还有一个小细节,就是需要对计算出的奖金保留1位小数。直接使用round(值,保留位数)进行处理即可。 

7.SQL 254 统计salary的累计和running_total

按照salary的累计和running_total,其中running_total为前N个当前( to_date = '9999-01-01')员工的salary累计和,其他以此类推。 

【SQL】牛客刷题笔记:SQL246~SQL254_第7张图片

这道题要求计算累加和,提到“累加”,自然就能想到窗口函数。窗口函数在SQL里应用很广,关于它的具体使用,后期我再详细写一篇和大家分享,其实并不是很难。窗口函数的语法格式如下:

<窗口函数> over (partition by <用于分组的列名> order by <用于排序的列名>)

select emp_no ,salary,sum(salary) over(order by emp_no)
from salaries
where to_date ="9999-01-01"

 这里先简单解释一下本题的思路。使用窗口函数对salary列进行累加求和,sum() over()即为求和,salary是需要求和的列,本题中并不需要进行分组(例如学生成绩表,需要对学生按照班级进行排名,这时就需要用到分组),只需要按照emp_no进行排序就可以了(排序一定要有的,毕竟是计算累加和,如果无序的话就成了计算所有的和了)。

这里再分享一个没有用到窗口函数的方法:

SELECT s2.emp_no,s2.salary,SUM(s1.salary) AS running_total
FROM salaries AS s1 INNER JOIN salaries AS s2
ON s1.emp_no <= s2.emp_no
WHERE
s1.to_date = "9999-01-01"
AND s2.to_date = "9999-01-01"
GROUP BY s2.emp_no

你可能感兴趣的:(MySQL,sql,笔记,数据库)