牛客数据库SQL实战 51-60(substr切割字符串、group_concat组拼接、limit_offset分页、exists条件成立判断、case分支、表的复用)


欢迎访问笔者个人技术博客: http://rukihuang.xyz/
牛客网数据库SQL实战

51* 获取Employees中的first_name

51.1 题目描述

获取Employees中的first_name,查询按照first_name最后两个字母,按照升序进行排列

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`));

输出格式:

first_name
Chirstian
Tzvetan
Bezalel
Duangkaew
Georgi
Kyoichi
Anneke
Sumant
Mary
Parto
Saniya

51.2 题解 substr

select 
	first_name
from 
	employees
order by
	substr(first_name, length(first_name)-1,length(first_name))
  • 本题考查 substr(X,Y,Z)substr(X,Y)函数的使用。其中X是要截取的字符串Y是字符串的起始位置(注意第一个字符的位置为1,而不为0),取值范围是±(1~length(X)),当Y等于length(X)时,则截取最后一个字符;当Y等于负整数-n时,则从倒数第n个字符处截取。Z是要截取字符串的长度,取值范围是正整数,若Z省略,则从Y处一直截取到字符串末尾;若Z大于剩下的字符串长度,也是截取到字符串末尾为止。

52* 按照dept_no进行汇总

52.1 题目描述

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

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`));

输出格式:

dept_noemployees
d00110001,10002
d00210006
d00310005
d00410003,10004
d00510007,10008,10010
d00610009,10010

52.2 题解 group_concat(字段名,分隔符)

select 
	dept_no
	,group_concat(emp_no, ",")
from 
	dept_emp
group by
	dept_no
  • 本题要用到SQLite的聚合函数group_concat(X,Y),其中X是要连接的字段,Y是连接时用的符号,可省略,默认为逗号。此函数必须与 GROUP BY 配合使用。此题以 dept_no 作为分组,将每个分组中不同的emp_no用逗号连接起来(即可省略Y)。

53 查找排除当前最大、最小salary之后的员工的平均工资avg_salary

53.1 题目描述

查找排除当前最大、最小salary之后的员工的平均工资avg_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`));

输出格式:

avg_salary
69462.5555555556

53.2 题解

  • 正常逻辑,OJ过不了
select
	avg(salary) as avg_salary
from 
	salaries
where
	salary not in(
		-- 1 找到最高工资和最小工资的salary
		(select	
			max(salary)
		from 
			salaries
		where 
			to_date = '9999-01-01') -- OJ中需要把时间条件删除,才能过
		,(select
			min(salary)
		from 
			salaries
		where 
			to_date = '9999-01-01') -- OJ中需要把时间条件删除,才能过
	)
and
	to_date = '9999-01-01'

  • OJ通过题解
select
	avg(salary) as avg_salary
from 
	salaries
where
	salary not in(
		-- 1 找到最高工资和最小工资的salary
		(select	
			max(salary)
		from 
			salaries
		)
		,(select
			min(salary)
		from 
			salaries
		)
	)
and
	to_date = '9999-01-01'

54 分页查询employees表,每5行一页,返回第2页的数据

54.1 题目描述

分页查询employees表,每5行一页,返回第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`));

54.2 题解 limit offset

  • 方法一:利用 LIMITOFFSET 关键字。LIMIT 后的数字代表返回几条记录,OFFSET 后的数字代表从第几条记录开始返回==(第一条记录序号为0)==,也可理解为跳过多少条记录后开始返回。
select 
	*
from 
	employees
limit 
	5 -- 返回5条数据
offset
    5 -- 从第6条数据开始返回
  • 只利用 LIMIT 关键字。注意:在 LIMIT X,Y 中,Y代表返回几条记录,X代表从第几条记录开始返回(第一条记录序号为0),切勿记反。
select 
	*
from 
	employees
limit 
	5,5 -- 从第6条记录开始,返回4条数据(第1条数据是第0条数据)

55 获取所有员工的emp_no

55.1 题目描述

获取所有员工的emp_no、部门编号dept_no以及对应的bonus类型btype和received ,没有分配具体的员工不显示

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,
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`));
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`));

create table emp_bonus(
emp_no int not null,
received datetime not null,
btype smallint not null);

输出格式:

e.emp_nodept_nobtypereceived
10001d00112010-01-01
10002d00122010-10-01
10003d00432011-12-03
10004d00412010-01-01
10005d003
10006d002
10007d005
10008d005
10009d006
10010d005
10010d006

55.2 题解

select
	d.emp_no
	,d.dept_no
	,e.btype
	,e.recevied -- 这个字段是题目打错的,我日,建议击毙
from 
	dept_emp d
left join
	emp_bonus e
on 
	d.emp_no = e.emp_no
  • 正常题解:本题严谨的思路为,先将 employees与dept_emp 用 INNER JOIN 连接,挑选出分配了部门的员工,再用 LEFT JOIN 连接 emp_bonus(在前面的题中可看到此表),分配了奖金的员工显示奖金类型和授予时间,没分配奖金的员工则不显示。
SELECT 
	em.emp_no
	, de.dept_no
	, eb.btype
	, eb.recevied
FROM 
	employees AS em 
INNER JOIN 
	dept_emp AS de
ON 
	em.emp_no = de.emp_no
LEFT JOIN 
	emp_bonus AS eb 
ON 
	de.emp_no = eb.emp_no

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

56.1 题目描述

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

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 `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`));

输出格式:

emp_nobirth_datefirst_namelast_namegenderhire_date
100111953-11-07MarySluisF1990-01-22

56.2 题解 exists

  • 不使用exists
select 
    * 
from 
    employees
where 
    emp_no not in (
        select 
            emp_no
        from 
            dept_emp d
    )
  • 使用exists
select 
    * 
from 
    employees
where not exists (
    select 
        emp_no
    from 
    	dept_emp 
    where 
   		emp_no = employees.emp_no -- 外面的表一定要和存在条件的子表差生关联
)
SELECT 
	* 
FROM 
	employees 
WHERE emp_no NOT exists (
    SELECT 
    	emp_no 
   	FROM 
    	dept_emp)  -- 过不了,在 employees 中没有一条记录能使 (SELECT emp_no FROM dept_emp) 不成立。(SELECT emp_no FROM dept_emp) 没有跟 emplotees 产生联系,因为无论选中 employees 中的哪条记录,(SELECT emp_no FROM dept_emp) 都成立

57 获取employees中的行数据,且这些行也存在于emp_v中

57.1 题目描述

存在如下的视图:

create view emp_v as select * from employees where emp_no >10005;
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`));

获取employees中的行数据,且这些行也存在于emp_v中。注意不能使用intersect关键字。
输出格式:

emp_nobirth_datefirst_namelast_namegenderhire_date
100061953-04-20AnnekePreusigF1989-06-02
100071957-05-23TzvetanZielinskiF1989-02-10
100081958-02-19SaniyaKalloufiM1994-09-15
100091952-04-19SumantPeacF1985-02-18
100101963-06-01DuangkaewPiveteauF1989-08-24
100111953-11-07MarySluisF1990-01-22

57.2 题解

-- 这题真的智障
select 
    * 
from
    emp_v

58 获取有奖金的员工相关信息。

58.1 题目描述

获取有奖金的员工相关信息。

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 `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 emp_bonus(
emp_no int not null,
recevied datetime not null,
btype smallint not null);
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`));

给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。 bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%。 当前薪水表示to_date=‘9999-01-01’
输出格式:

emp_nofirst_namelast_namebtypesalarybonus
10001GeorgiFacello1889588895.8
10002BezalelSimmel27252714505.4
10003PartoBamford34331112993.3
10004ChirstianKoblick1740577405.7

58.2 题解 case…when…then…else…end

select 
	em.emp_no
	,em.first_name
	,em.last_name
	,eb.btype
	,s.salary 
	,(case eb.btype	
		when 1 then 0.1 * s.salary
		when 2 then 0.2 * s.salary
		else 0.3 * s.salary end ) as bonus
from
	employees em
left join 
    emp_bonus eb
on 
    em.emp_no = eb.emp_no
left join 
	salaries s
on 
	eb.emp_no = s.emp_no
where 
    s.to_date = '9999-01-01'

59* 统计salary的累计和running_total

59.1 题目描述

按照salary的累计和running_total,其中running_total为前两个员工的salary累计和,其他以此类推。 具体结果如下Demo展示。。

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`));

输出格式:

emp_nosalaryrunning_total
100018895888958
1000272527161485
1000343311204796
1000474057278853
1000594692373545
1000643311416856
1000788070504926
1000995409600335
1001094409694744
1001125828720572

59.2 题解

本题的思路为复用 salaries 表进行子查询,最后以 s1.emp_no 排序输出求和结果。

1、输出的第三个字段,是由一个 SELECT 子查询构成。将子查询内复用的 salaries 表记为 s2,主查询的 salaries 表记为 s1,当主查询的 s1.emp_no 确定时,对子查询中不大于 s1.emp_no 的 s2.emp_no 所对应的薪水求和

2、注意是对员工当前的薪水求和,所以在主查询和子查询内都要加限定条件 to_date = ‘9999-01-01’

select 
	s2.emp_no
	,s2.salary
	,(
		select 
			sum(salary)
		from 
			salaries s1
		where 
			s1.emp_no <= s2.emp_no -- 复用两张表
		and 
			s1.to_date = '9999-01-01'
	) as running_total
from 
	salaries s2
where 
	s2.to_date = '9999-01-01'

60* 对于employees表中,给出奇数行的first_name

60.1 题目描述

对于employees表中,给出奇数行的first_name

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`));

输出格式:

first_name
Georgi
Chirstian
Anneke
Tzvetan
Saniya
Mary

60.2 题解

SELECT 
	E1.first_name 
FROM 
	employees E1
WHERE (
	SELECT 
		COUNT(*)  -- 序号 复用2张表,先对first_name进行排序,count(*)就是序号
	FROM 
		employees E2 
	WHERE 
		E1.first_name >= E2.first_name) % 2 = 1;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值