SQL 牛客网刷题02——中等

目录

1、 查找当前薪水详情以及部门编号dept_no

2、查找已经分配部门的员工的last_name和first_name以及dept_no,也包括暂时没有分配具体部门的员工

 3、获取员工和对应的经理,如果员工本身是经理的话则不显示

4、各个title类型对应的员工薪水对应的平均工资avg

5、所有员工的last_name和first_name以及对应的dept_name,包括未分配员工

6、计各个部门的工资记录数

7、使用join查询方式找出没有分类的电影id以及其电影名称

8、使用子查询的方式找出属于Action分类的所有电影对应的title,description

9、创建一个actor表

10、批量插入数据,不使用replace操作

11、对first_name创建唯一索引,对last_name创建普通索引

12、针对actor表创建视图actor_name_view

13、针对salaries表emp_no字段创建强制索引idx_emp_no

14、在last_update后面新增加一列名字为create_date

15、构造一个触发器audit_log

16、audit表上创建外键约束,其emp_no对应employees_test表的主键id

17、将所有获取奖金的员工当前的薪水增加10%

18、所有员工的last_name和first_name通过(')连接起来

19、查找字符串中逗号出现的次数

 20、获取employees中的first_name,按最后两个字母升序

21、按照dept_no进行汇总

22、平均工资

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

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

25、刷题通过的题目排名

 26、考试分数(二)

27、牛客的课程订单分析(二)

28、牛客的课程订单分析(三)

29、牛客的课程订单分析(六)

30、实习广场投递简历分析(二)

31、 最差是第几名(一)

32、获得积分最多的人(一)

33、商品交易(网易校招笔试真题

34、今天的刷题量(一)

35、 创建一个actor_name表


1、 查找当前薪水详情以及部门编号dept_no

SQL 牛客网刷题02——中等_第1张图片

 各个部门当前领导的薪水详情以及其对应部门编号dept_no,salaries.emp_no升序:

# 方法一
select s., d.dept_no from dept_manager d, salaries s
where d.emp_no=s.emp_no
and d.to_date='9999-01-01' and s.to_date='9999-01-01'
order by emp_no;

# 方法二:内联结
select s.*, d.dept_no from salaries as s
inner join dept_manager as d on s.emp_no = d.emp_no
order by s.emp_no;

2、查找已经分配部门的员工的last_name和first_name以及dept_no,也包括暂时没有分配具体部门的员工

SQL 牛客网刷题02——中等_第2张图片

# 部分员工还没有分配到部门,因此不能使用内连接,使用左连接确保员工没有缺失
select last_name, first_name, dept_no
from employees em
left join dept_emp dm
on em.emp_no = dm.emp_no

 3、获取员工和对应的经理,如果员工本身是经理的话则不显示

select d.emp_no, de.emp_no as manager from dept_emp d
inner join dept_manager de 
on d.dept_no = de.dept_no 
where d.emp_no != de.emp_no;

4、各个title类型对应的员工薪水对应的平均工资avg

SQL 牛客网刷题02——中等_第3张图片

# 经过 group by 之后,select 中只能包含分组的字段以及聚合函数
select t.title, avg(s.salary) from titles t
inner join salaries s
on t.emp_no = s.emp_no
group by title
order by avg(s.salary);

5、所有员工的last_name和first_name以及对应的dept_name,包括未分配员工

题目有三个表:

【部门的信息】departments: dept_no, dept_name

【部门员工所属】dept_emp: emp_no, dept_no,...

【员工的信息】employees: emp_no, first_name, last_name,...

# 方法一:两次left join嵌套
SELECT last_name, first_name, dept_name
FROM employees AS e LEFT JOIN (SELECT emp_no, dept_name
                               FROM dept_emp AS de LEFT JOIN departments AS d
                               ON de.dept_no = d.dept_no)k
ON e.emp_no = k.emp_no;

# 方法二:两次LEFT JOIN连接
select e.last_name, e.first_name, dept_name from employees e
left join dept_emp de on e.emp_no = de.emp_no
left join departments d on de.dept_no = d.dept_no;

6、计各个部门的工资记录数

给出部门编码dept_no、部门名称dept_name以及部门在salaries表里面有多少条记录sum,按照dept_no升序排序

# 方法一:窗口函数count()over()
select distinct d.dept_no , d.dept_name,
count(s.salary)over(partition by d.dept_no order by d.dept_no)
from departments as d join dept_emp as de on d.dept_no = de.dept_no
                      join salaries as s  on s.emp_no = de.emp_no;

# 方法二:三表连结再分组使用聚合函数
# 当group by 后面跟上主键或者不为空唯一索引时,查询是有效的,因为此时的每一笔数据都具有唯一性。
select de.dept_no, de.dept_name,count(s.salary) from departments de
inner join dept_emp d on de.dept_no = d.dept_no
inner join salaries s on d.emp_no = s.emp_no
group by de.dept_no
order by de.dept_no;

7、使用join查询方式找出没有分类的电影id以及其电影名称

# 方法一:内连接+not in
select film_id as '电影id',title as '名称'
from film
where film_id not in(select f.film_id
from film f inner join film_category fc on f.film_id=fc.film_id);

# 方法二:左连接+is null
select f.film_id, f.title from film f 
left join film_category fc on f.film_id=fc.film_id
where fc.category_id is null;

8、使用子查询的方式找出属于Action分类的所有电影对应的title,description

select title, description from film f
where f.film_id in (select film_id from film_category fc 
                    inner join category c  
                    on fc.category_id = c.category_id 
                    where name = 'Action');   

9、创建一个actor表

create table actor
(actor_id smallint(5) not null COMMENT '主键id',
 first_name varchar(45) not null COMMENT '名字',
 last_name	varchar(45) not null COMMENT '姓氏',
 last_update date not null COMMENT '日期',
 PRIMARY KEY (actor_id)
);

10、批量插入数据,不使用replace操作

# mysql中常用的三种插入数据的语句:
# insert into表示插入数据,数据库会检查主键,如果出现重复会报错;
# replace into表示插入替换数据,需求表中有PrimaryKey,
#             或者unique索引,如果数据库已经存在数据,则用新数据替换,如果没有数据效果则和insert into一样;

# insert ignore表示,如果中已经存在相同的记录,则忽略当前新数据;
insert ignore into actor values("3","ED","CHASE","2006-02-15 12:34:33");

11、对first_name创建唯一索引,对last_name创建普通索引

# 添加主键 意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD PRIMARY KEY (col_list);

# 添加唯一索引 
ALTER TABLE tbl_name ADD UNIQUE index_name (col_list);

# 添加普通索引
ALTER TABLE tbl_name ADD INDEX index_name (col_list);

# 添加全文索引
ALTER TABLE tbl_name ADD FULLTEXT index_name (col_list);

# 添加多列索引
ALTER TABLE 表名 ADD UNIQUE (col1, col2, ..., )

# 删除索引
DROP INDEX index_name ON tbl_name; 
ALTER TABLE tbl_name DROP INDEX index_name;
ALTER TABLE tbl_name DROP PRIMARY KEY;

# 该语句指定了索引可以是唯一索引、全文索引、空间索引以及普通索引。
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name ON tbl_name (col_name);

# Alter可以省略索引名。如果省略索引名,数据库会默认根据第一个索引列赋予一个名称;Create必须指定索引名称;Create不能用于创建Primary key索引;Alter允许一条语句同时创建多个索引;Create一次只能创建一个索引

alter table actor add unique uniq_idx_firstname(first_name);
alter table actor add index idx_lastname(last_name);

12、针对actor表创建视图actor_name_view

# 方法一:直接在视图名的后面用小括号创建视图中的字段名
create view actor_name_view (first_name_v,last_name_v) as
select first_name ,last_name from actor;

# 方法二:在select后面对列重命名为视图的字段名
create view actor_name_view as
select first_name as first_name_v,last_name as last_name_v
from actor;

13、针对salaries表emp_no字段创建强制索引idx_emp_no

select * from salaries
force index(idx_emp_no)
where emp_no=10005;

14、在last_update后面新增加一列名字为create_date

# 最后一列增加列:alter table 表名 add column ……
# 指定位置增加列:alter table 表名 add column ……after列名
# 在第一列增加列:alter table 表名 add column ……first

alter table actor add column create_date datetime NOT NULL default '2020-10-01 00:00:00'

15、构造一个触发器audit_log

在向employees_test表中插入一条数据的时候,触发插入相关的数据到audit中

create trigger audit_log
after insert on employees_test
for each row  # 影响每一行
begin
 	insert into audit values(new.id,new.name);
end;

# INSERT型,NEW 用来表示将要(BEFORE)或已经(AFTER)插入的新数据;
# UPDATE,OLD 用来表示将要或已经被修改的原数据,NEW 用来表示将要或已经修改为的新数据;
# DELETE,OLD 用来表示将要或已经被删除的原数据;

16、audit表上创建外键约束,其emp_no对应employees_test表的主键id

# 创建外键语句结构:
ALTER TABLE <表名>
ADD CONSTRAINT FOREIGN KEY (<列名>)
REFERENCES <关联表>(关联列)

alter table audit add
constraint audit_foreign_key_emp_no foreign key(emp_no)
references employees_test(id);

17、将所有获取奖金的员工当前的薪水增加10%

# 方法一:子查询
update salaries
set salary=salary*1.1
where to_date='9999-01-01'
    and salaries.emp_no in(select emp_no from emp_bonus)

# 方法二:连接查询(先join两张表)
update salaries as s join emp_bonus as e on s.emp_no=e.emp_no
set salary=salary*1.1
where to_date='9999-01-01'

18、所有员工的last_name和first_name通过(')连接起来

# concat(字段1,字段2,……)
select concat(last_name, "'", first_name) AS name from employees

19、查找字符串中逗号出现的次数

SQL 牛客网刷题02——中等_第4张图片

# 用原字符串的长度减去除去了逗号的字符串长度,得到逗号出现的次数
# length(string)  计算字符串的长度
# replace(string,'被替换的字符','用于替换的字符')
# 在这里我们用空替换逗号
select id,
  length(string)-length(replace(string,',','') ) as cnt
from strings

 20、获取employees中的first_name,按最后两个字母升序

# 方法一:right
select first_name from employees
order by right(first_name,2);

# 方法二:substr
select first_name from employees  order by substr(first_name,-2)

# 方法三:substring
select first_name from employees  order by substring(first_name,-2)

21、按照dept_no进行汇总

# group_concat()函数将group by产生的同一个分组中的值连接起来,返回一个字符串结果。

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

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

22、平均工资

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

# 方法一:聚合函数
# COUNT(1) 代表所有数据长度, -2 代表减去最大最小值的两个长度
SELECT (SUM(salary) - MAX(salary) - MIN(salary)) / (COUNT(1)-2) avg_salary 
FROM salaries where to_date = '9999-01-01';

# 方法二
select avg(salary) as 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')

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

# LIMIT X,Y  Y返回几条记录,X从第几条记录开始返回(第一条记录序号为0,默认为0)
select * from employees
limit 5,5

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

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

25、刷题通过的题目排名

输出通过的题目的排名,通过题目个数相同的,排名相同,此时按照id升序排列

SQL 牛客网刷题02——中等_第5张图片

# 方法一:dense_rank()
# row_number()对应唯一排序:1、2、3、4
# dense_rank()对应相同次序可重复,但不跳过下一个次序值:1、2、2、3
# rank()对应相同次序可重复,并且跳过下一个次序值:1、2、2、4
select id,number,
dense_rank()over(order by number desc) as t_rank
from passing_number
order by t_rank,id;

# 方法二:使用where子查询
select p1.id ,p1.number,
(select count(distinct p2.number) from passing_number as p2 where p2.number >= p1.number) as t_rank
from passing_number as p1
order by number desc,id asc

 26、考试分数(二)

查询用户分数大于其所在工作(job)分数的平均分的所有grade的属性,并且以id的升序排序

# 方法一:窗口函数
SELECT t.id,t.job,t.score
FROM (SELECT *,AVG(score) OVER(PARTITION BY job) AS avg_sco 
      FROM grade) t
WHERE t.score > t.avg_sco
ORDER BY t.id ASC;

# where子查询
SELECT g.id,g.job,g.score
FROM grade g
WHERE g.score > (SELECT AVG(score)
                  FROM grade g1
                  WHERE g.job = g1.job
                  GROUP BY job)
ORDER BY id ASC;

27、牛客的课程订单分析(二)

查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的user_id,并且按照user_id升序排序

# where子句中不能使用聚合函数,聚合函数可以在select,having,order by之后出现
SELECT user_id FROM order_info WHERE date > '2025-10-15'
AND status LIKE 'c%'
AND product_name IN ('C++', 'Java', 'Python')
GROUP BY user_id HAVING COUNT(user_id) >= 2
ORDER BY user_id;

28、牛客的课程订单分析(三)

查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的订单信息,并且按照order_info的id升序

# 方法一:窗口函数
select t1.id, t1.user_id,t1.product_name,t1.status,t1.client_id,t1.date
from
(
    select *,count(id) over(partition by user_id) as number
    from order_info
    where datediff(date,"2025-10-15")>0
      and status ="completed"
      and product_name in ("C++","Java","Python")
) t1
where t1.number >1
order by t1.id

# 方法二
select * from order_info
where user_id in (select user_id from order_info
                    where status = 'completed'
                    and date > '2025-10-15'
                    and product_name in ('C++', 'Java', 'Python')
                    group by user_id
                    having count(user_id) > 1)
and status = 'completed'
and date > '2025-10-15'
and product_name in ('C++', 'Java', 'Python')
order by id

29、牛客的课程订单分析(六)

查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的订单id,是否拼团以及客户端名字信息,最后一列如果是非拼团订单,则显示对应客户端名字,如果是拼团订单,则显示NULL,并且按照order_info的id升序排序

# 表连接时需要使用left join来左连结order_info表,因为client_id = 0这个数据在client表里是不存在的,会在连结时被去掉
select t.id, t.is_group_buy, c.name as client_name
from (
    select id, is_group_buy, client_id,
    count(*) over (partition by user_id) as cnt
    from order_info
    where date > '2025-10-15'
    and product_name in ('C++', 'Python', 'Java')
    and status = 'completed'
    ) as t
left join client as c
on c.id = t.client_id
where t.cnt >= 2
order by t.id

30、实习广场投递简历分析(二)

查询在2025年内投递简历的每个岗位,每一个月内收到简历的数量,并且按先按月份降序排序,再按简历数目降序排序

select job,date_format(date,'%Y-%m') as mon,sum(num) as cnt
from resume_info
where date like '2025%'  -- 符合最左前缀匹配原则,也走索引
group by job,mon
order by mon desc,cnt desc;

31、 最差是第几名(一)

如果一个学生知道了自己综合成绩以后,最差是排第几名? 结果按照grade升序排序

# 方法一:窗口函数
select grade, sum(number) over(order by grade) t_rank 
from class_grade 
order by grade;

# 方法二:case when then end
SELECT grade,
# 如果等级为A,将小于等于A的人数相加  作为最差名次
(CASE grade WHEN 'A' THEN (SELECT SUM(number) FROM class_grade WHERE grade<='A')  
WHEN 'B' THEN (SELECT SUM(number) FROM class_grade WHERE grade <='B') 
WHEN 'C' THEN (SELECT SUM(number) FROM class_grade WHERE grade <='C') 
WHEN 'D' THEN (SELECT SUM(number) FROM class_grade WHERE grade <='D') 
ELSE (SELECT SUM(number) FROM class_grade ) 
END )AS t_rank
FROM class_grade
ORDER BY grade; 

32、获得积分最多的人(一)

查找积分增加最高的用户的名字,以及他的总积分是多少(此题保证积分最高的用户有且只有1个)

select name,sum(grade_num)over(partition by user_id) as grade_sum
from grade_info,user
where grade_info.user_id = user.id
order by grade_sum desc
limit 1

33、商品交易(网易校招笔试真题

select g.id, g.name, g.weight,sum(t.count) as total from goods g
left join trans t on g.id = t.goods_id
group by g.id
having total > 20 and g.weight < 50
order by g.id;

34、今天的刷题量(一)

查找出当天每个题单的刷题量,先按提交数量降序排序,提交数量一样,按subject_id升序排序

select s.name,count(su.subject_id) as cnt from submission su
inner join subject s on su.subject_id = s.id
where su.create_time = current_date
group by s.name,su.subject_id  # order by后面的字段需要在group中出现
order by cnt desc,subject_id;

35、 创建一个actor_name表

create table if not exists actor_name (
    first_name varchar(45)    not null comment '名字',
    last_name    varchar(45)    not null comment '姓氏');
insert into actor_name 
SELECT first_name,last_name FROM actor;

你可能感兴趣的:(SQL,sql,数据库)