请你将employees中的first_name,并按照first_name最后两个字母升序进行输出。
该题与SQL213、SQL226、SQL244类似,都考察了字符串相关的函数。本题所考察的函数是字符串截取函数substr(str,index,len)。该函数用法如下:
subtring(字符串,截取的起始位置,截取的字符数)
index从1开始,第三个参数可以省略,表示截取到最后一位
本题中要求从从末尾截取,从后往前数使用负数表示。
select first_name
from employees
order by substr(first_name,-2)
按照dept_no进行汇总,属于同一个部门的emp_no按照逗号进行连接,结果给出dept_no以及连接出的结果employees。
改题目仍旧属于对字符串函数的考察 ,这里使用的函数是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
查找排除在职(to_date = '9999-01-01' )员工的最大、最小salary之后,其他的在职员工的平均工资avg_salary。
本题需要求平均工资,但限定了员工范围为在职员工(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")
本题考查分页查询,分页查询也是在业务场景中经常遇到的情况,使用limit()函数即可解决。
limit x, y: x:表示偏移量(从0开始), y:表示获取的数据数量
计算分页的公式:limit (页数-1)*每页显示行数,每页显示行数
select * from employees limit 5,5
使用含有关键字exists查找未分配具体部门的员工的所有信息。
本题的常规解答是使用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查询的效率较高;
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升序排序。
本题的难点在于多表连接,以及对奖金金额的计算。需要注意的是对薪水的查询限定了是当前的薪水情况( 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(值,保留位数)进行处理即可。
按照salary的累计和running_total,其中running_total为前N个当前( to_date = '9999-01-01')员工的salary累计和,其他以此类推。
这道题要求计算累加和,提到“累加”,自然就能想到窗口函数。窗口函数在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