MySQL:怒刷牛客网“sql实战”
MySQL:怒刷牛客网“sql实战”
SQL1
查找最晚入职员工的所有信息
select
*
from
employees
where
employees.hire_date
==(select max(hire_date) from employees);
SQL2
查找入职员工时间排名倒数第三的员工所有信息
select * from employees
where hire_date =
(
select
distinct hire_date -- 这里的distinct需要注意
from
employees
order by
hire_date desc
limit 2,1
);
SQL3
查找各个部门当前领导当前薪水详情以及其对应部门编号dept_no
select
s.emp_no, s.salary, s.from_date, s.to_date, d.dept_no
from
salaries s,
dept_manager d
where
d.to_date='9999-01-01' and s.to_date='9999-01-01' and d.emp_no = s.emp_no
order by
s.emp_no;
SQL4:
查找所有已经分配部门的员工的last_name和first_name
select
e.last_name, e.first_name, d.dept_no
from
dept_emp d,
employees e
where
d.emp_no = e.emp_no;
SQL5
查找所有员工的last_name和first_name以及对应部门编号dept_no
select
e.last_name, e.first_name, d.dept_no
from
employees e
left join
dept_emp d
on
e.emp_no = d.emp_no;
SQL7
查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
-- 解法1:
select
distinct s.emp_no, cs.times as t
from
salaries as s,
(
select
count(*) as times, salaries.emp_no as emp_no
from
salaries
group by
salaries.emp_no
) as cs
where
cs.times > 15 and cs.emp_no = s.emp_no;
-- 解法2:
select
salaries.emp_no, count(*) as t
from
salaries
group by salaries.emp_no having count(*)>15;
SQL8
找出所有员工当前具体的薪水salary情况
select
distinct salaries.salary
from
salaries
where
salaries.to_date='9999-01-01'
order by salaries.salary desc;
SQL10
获取所有非manager的员工emp_no
select
e.emp_no
from
employees e
where e.emp_no not in (select d.emp_no from dept_manager d);
SQL11
获取所有员工当前的manager
-- 第一步:找出所有的manager
select
d.emp_no
from
dept_manager d
where
d.to_date='9999-01-01';
-- 第二步:找出不是manage的员工
select
e.emp_no, e.dept_no
from
dept_emp e
where e.emp_no not in (
select d.emp_no from dept_manager d where d.to_date='9999-01-01'
);
-- 最后:再根据e.emp_no, e.dept_no找出其manager对应的emp_no
select
ed.emp_no, d.emp_no
from
dept_manager d,
(select
e.emp_no, e.dept_no
from
dept_emp e
where
e.emp_no not in (select d.emp_no from dept_manager d where d.to_date='9999-01-01')) as ed
where
ed.dept_no = d.dept_no and d.to_date='9999-01-01';
SQL12
获取所有部门中当前员工薪水最高的相关信息
-- 取各部门中薪水最高
SELECT
de.dept_no, de.emp_no, MAX(s.salary) AS max_salary
FROM
dept_emp de INNER JOIN salaries s ON de.emp_no=s.emp_no
WHERE
de.to_date='9999-01-01' AND s.to_date='9999-01-01'
GROUP BY
de.dept_no;
-- 错误代码:!!!GROUP BY 默认取非聚合的第一条记录!!!!!!
-- 因此进行MAX(s.salary)会出现数据不匹配的情况出现
-- 方式1:
-- 第一步:取各部门中薪水最高
SELECT
de.dept_no, de.emp_no, MAX(s.salary) AS max_salary
FROM
dept_emp de INNER JOIN salaries s ON de.emp_no=s.emp_no
WHERE
de.to_date='9999-01-01' AND s.to_date='9999-01-01'
GROUP BY
de.dept_no;
-- 第二补:进行后续匹配
select
de.dept_no, de.emp_no, tab.max_salary
from
dept_emp de, salaries s,
(SELECT
de.dept_no, de.emp_no, MAX(s.salary) AS max_salary
FROM
dept_emp de INNER JOIN salaries AS s ON de.emp_no=s.emp_no
WHERE
de.to_date='9999-01-01' AND s.to_date='9999-01-01'
GROUP BY
de.dept_no) as tab
where
tab.max_salary = s.salary
and s.emp_no = de.emp_no
and tab.dept_no = de.dept_no
and de.to_date='9999-01-01' and s.to_date='9999-01-01'
order by
de.dept_no;
-- 方式2:和上述方式1大同小异
SELECT
d.dept_no, d.emp_no, sub_tab.max_salary
FROM
dept_emp d, salaries s,
(SELECT
d.`dept_no`, MAX(s.salary) AS max_salary
FROM
dept_emp d INNER JOIN salaries s
ON
d.to_date = '9999-01-01'
AND s.to_date = '9999-01-01'
AND d.`emp_no` = s.`emp_no`
GROUP BY
d.`dept_no`) AS sub_tab
WHERE
d.dept_no = sub_tab.dept_no
AND s.salary = sub_tab.max_salary
AND d.emp_no = s.emp_no
AND d.to_date = '9999-01-01'
AND s.to_date = '9999-01-01'
ORDER BY d.dept_no;
SQL15
查找employees表所有emp_no为奇数
SELECT
*
FROM
employees
WHERE
employees.`last_name` != "Mary" AND employees.`emp_no` % 2=1
ORDER BY
employees.`hire_date` DESC;
SQL16
统计出当前各个title类型对应的员工当前薪水对应的平均工资
SELECT
t.title, AVG(s.salary)
FROM
titles t
JOIN
salaries s
ON
t.emp_no = s.emp_no
WHERE
t.to_date='9999-01-01' AND s.to_date='9999-01-01'
GROUP BY
t.title;
SQL17
获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
-- 最高的salary没有重复的解法:
SELECT
s.emp_no, s.salary
FROM
salaries s
WHERE
s.to_date='9999-01-01'
GROUP BY
s.emp_no
ORDER BY
s.salary DESC
LIMIT 1,1;
-- 更加标准的解法:最高salary重复也没关系
select
s.emp_no, s.salary
from
salaries s
where
s.salary =
(select distinct s.salary from salaries s where s.to_date = '9999-01-01' order by s.salary desc limit 1, 1);
SQL18
查找当前薪水排名第二多的员工编号emp_no
-- 解法1:题目要求是不能使用order by完成
-- 第一步:先找出最大薪水
SELECT
MAX(salaries.salary) AS max_salary
FROM
salaries
WHERE
salaries.to_date='9999-01-01'
-- 第二步:找出第二大薪水
SELECT
MAX(s.salary) AS second_max
FROM
salaries s,
(SELECT
MAX(salaries.salary) AS max_salary
FROM
salaries
WHERE
salaries.to_date='9999-01-01') AS ss
WHERE
s.salary != max_salary AND s.to_date='9999-01-01';
-- 最后:对应的员工信息
SELECT
e.emp_no, s.salary, e.last_name, e.first_name
FROM
employees e,
salaries s,
(SELECT
MAX(s.salary) AS second_max
FROM
salaries s,
(SELECT
MAX(salaries.salary) AS max_salary
FROM
salaries
WHERE
salaries.to_date='9999-01-01') AS ss
WHERE
s.salary != max_salary AND s.to_date='9999-01-01') ss
WHERE
s.salary = ss.second_max AND s.emp_no = e.emp_no;
-- 解法2:使用order by,但是无法通过,因为题目要求无法使用orderby
-- 第一步:找薪水第二大的
select
s.emp_no, s.salary
from
salaries s
where
s.salary =
(select distinct s.salary from salaries s where s.to_date = '9999-01-01' order by s.salary desc limit 1, 1);
-- 第二步:根据薪水第二大的会去查找对应的员工
select
e.emp_no, tab.salary, e.last_name, e.first_name
from
(select
s.emp_no, s.salary as salary
from
salaries s
where
s.salary =
(select distinct s.salary from salaries s where s.to_date = '9999-01-01' order by s.salary desc limit 1, 1)
) as tab,
employees as e
where
tab.emp_no = e.emp_no;
SQL19
查找所有员工的last_name和first_name以及对应的dept_name
-- 第一步:先合并department表和dept_emp表
SELECT
d.dept_name, de.emp_no
FROM
dept_emp de
INNER JOIN
departments d
ON
de.dept_no = d.dept_no;
-- 第二步:加上员工信息
SELECT
e.last_name, e.first_name, d.dept_name
FROM
employees e
LEFT JOIN
(SELECT
d.dept_name, de.emp_no
FROM
dept_emp de
INNER JOIN
departments d
ON
de.dept_no = d.dept_no) d
ON
e.emp_no = d.emp_no;
SQL21
查找所有员工自入职以来的薪水涨幅情况
-- 第一步:查出入职薪水
SELECT
e.`emp_no`, s.`salary` AS hire_salary
FROM
employees e,
salaries s
WHERE
e.`emp_no` = s.`emp_no` AND e.`hire_date` = s.`from_date`;
-- 第二步:最终薪水
SELECT
e.`emp_no`, s.`salary` AS last_salary
FROM
employees e,
salaries s
WHERE
e.`emp_no` = s.`emp_no` AND s.`to_date`='9999-01-01';
-- 第三步:结合上述两张表,给出最终结果
SELECT
salary_1.emp_no, (salary_2.last_salary - salary_1.hire_salary) AS growth
FROM
(SELECT
e.`emp_no`, s.`salary` AS hire_salary
FROM
employees e,
salaries s
WHERE
e.`emp_no` = s.`emp_no` AND e.`hire_date` = s.`from_date`) AS salary_1,
(SELECT
e.`emp_no`, s.`salary` AS last_salary
FROM
employees e,
salaries s
WHERE
e.`emp_no` = s.`emp_no` AND s.`to_date`='9999-01-01') AS salary_2
WHERE
salary_1.emp_no = salary_2.emp_no
ORDER BY
growth;
SQL22
统计各个部门的工资记录数
SELECT
d.`dept_no`, d.`dept_name`, COUNT(s.`salary`) AS `sum`
FROM
dept_emp de
JOIN
salaries s
ON
de.`emp_no` = s.`emp_no`
JOIN
departments d
ON
de.`dept_no` = d.`dept_no`
GROUP BY
d.`dept_no`;
SQL23
对所有员工的当前薪水按照salary进行按照1-N的排名
-- 标准答案,参考了讨论区
SELECT
s1.emp_no, s1.salary,
COUNT(DISTINCT s2.salary) AS rank
FROM
salaries AS s1,
salaries AS s2
WHERE
s1.to_date = '9999-01-01' AND s2.to_date = '9999-01-01'
AND s1.salary <= s2.salary
GROUP BY
s1.emp_no
ORDER BY
s1.salary DESC, s1.emp_no ASC;
-- 本题的精髓在于:
-- s1.salary <= s2.salary,
-- 意思是在输出s1.salary的情况下,有多少个s2.salary大于等于s1.salary
-- 最后再利用COUNT(DISTINCT s2.salary)去重
SQL24
获取所有非manager员工当前的薪水情况
-- 写法1:
SELECT
de.`dept_no`, e.`emp_no`, s.`salary`
FROM
employees e
JOIN
dept_emp de
ON
e.`emp_no` = de.`emp_no`
JOIN
salaries s
ON
e.`emp_no` = s.`emp_no` AND s.`to_date`='9999-01-01'
WHERE
e.`emp_no` NOT IN (
SELECT
dm.`emp_no`
FROM
dept_manager dm
WHERE
dm.`to_date`='9999-01-01');
-- 写法2:注意多表联查的问题!!! 最好还是用join连接表
SELECT
de.`dept_no`, e.`emp_no`, s.`salary`
FROM
dept_emp de,
employees e,
salaries s,
(SELECT
dm.`emp_no`
FROM
dept_manager dm
WHERE
dm.`to_date`='9999-01-01') AS m
WHERE
e.`emp_no` = de.`emp_no`
AND e.`emp_no` = s.`emp_no`
AND s.`to_date`='9999-01-01'
AND (e.`emp_no` NOT IN (m.`emp_no`))
SQL25
获取员工其当前的薪水比其manager当前薪水还高的相关信息
-- 第一步:找出manager的薪水
SELECT
dm.`emp_no`, dm.`dept_no`, s.`salary`
FROM
dept_manager dm,
salaries s
WHERE
dm.`emp_no` = s.`emp_no`
AND dm.`to_date`='9999-01-01'
AND s.`to_date`='9999-01-01';
-- 第二步:将dept_emp表和salaries表相连,即查出所有人的薪水
SELECT
de.`emp_no`, de.`dept_no`, s.`salary`
FROM
dept_emp de
JOIN
salaries s
ON
de.`emp_no` = s.`emp_no`
AND de.`to_date`= '9999-01-01'
AND s.`to_date`='9999-01-01';
-- 第三步:融合上述两张表
SELECT
e_tab.emp_no AS emp_no, m_tab.emp_no AS manager_no, e_tab.salary AS emp_salary, m_tab.salary AS manager_salary
FROM
(SELECT
dm.`emp_no`, dm.`dept_no`, s.`salary`
FROM
dept_manager dm,
salaries s
WHERE
dm.`emp_no` = s.`emp_no`
AND dm.`to_date`='9999-01-01'
AND s.`to_date`='9999-01-01') AS m_tab, -- manager的薪水
(SELECT
de.`emp_no`, de.`dept_no`, s.`salary`
FROM
dept_emp de
JOIN
salaries s
ON
de.`emp_no` = s.`emp_no`
AND de.`to_date`= '9999-01-01'
AND s.`to_date`='9999-01-01'
) AS e_tab -- 所有人的薪水表
WHERE
m_tab.dept_no = e_tab.dept_no -- 1.部门相同
AND m_tab.emp_no != e_tab.emp_no -- 2.不是部门manager
AND m_tab.salary < e_tab.salary; -- 3.员工的薪水比你manager高
SQL26
汇总各个部门当前员工的title类型的分配数目
SELECT
d.`dept_no`, d.`dept_name`, t.`title`, COUNT(t.`title`)
FROM
dept_emp de
JOIN
titles t
ON
de.`emp_no` = t.`emp_no`
AND de.`to_date`='9999-01-01'
AND t.`to_date`='9999-01-01'
JOIN
departments d
ON
d.`dept_no`=de.`dept_no`
GROUP BY
d.`dept_no`, t.`title` -- 这里是关键
SQL28
查找描述信息中包括robot的电影对应的分类名称以及电影数目
-- 第一步:先将找出含有robot描述信息的电影
SELECT
f.`film_id`
FROM
film f
WHERE
f.`description` LIKE "%robot%";
-- 第二步:先将找出含有robot描述信息的电影+其类别id
SELECT
f.`film_id`, fc.`category_id`
FROM
film f
JOIN
film_category fc
ON
f.`film_id` = fc.`film_id`
WHERE
f.`description` LIKE "%robot%";
-- 第三步:先将找出含有robot描述信息的电影+其类别+类别名称
SELECT
f.`film_id`, fc.`category_id`, c.`name`
FROM
film f
JOIN
film_category fc
ON
f.`film_id` = fc.`film_id`
JOIN
category c
ON
fc.`category_id` = c.`category_id`
WHERE
f.`description` LIKE "%robot%";
-- 最终:分类包含电影总数量(count(film_category.category_id))>=5部
SELECT
fcn.`name`, COUNT(DISTINCT fcn.`film_id`) -- 注意这个DISTINCT!!!
FROM
film_category fc,
(SELECT
f.`film_id`, fc.`category_id`, c.`name`
FROM
film f
JOIN
film_category fc
ON
f.`film_id` = fc.`film_id`
JOIN
category c
ON
fc.`category_id` = c.`category_id`
WHERE
f.`description` LIKE "%robot%") fcn
WHERE
fc.`category_id` = fcn.`category_id`
GROUP BY
fc.`category_id`
HAVING
COUNT(fc.`film_id`)>=5; -- 该分类的部数要大于5
SQL29
使用join查询方式找出没有分类的电影id以及名称
-- 第一步:根据电影id找出其对应的类别id,用左外连接,然后再一个左外连接查出对应的类别名称
SELECT
f.`film_id`, f.`title`, c.`name`
FROM
film f
LEFT JOIN
film_category fc
ON
f.`film_id` = fc.`film_id`
LEFT JOIN
category c
ON
fc.`category_id` = c.`category_id`
-- 第二步:找名字是null的就可以了
SELECT
t.`film_id`, t.`title`
FROM
(SELECT
f.`film_id`, f.`title`, c.`name`
FROM
film f
LEFT JOIN
film_category fc
ON
f.`film_id` = fc.`film_id`
LEFT JOIN
category c
ON
fc.`category_id` = c.`category_id`) AS t
WHERE
t.name IS NULL;
SQL30
使用子查询的方式找出属于Action分类的所有电影对应的title,description
-- 查询1: 根据电影id查出电影对应的类别id
SELECT f.`title`, f.`description`, fc.`category_id` FROM film AS f JOIN film_category fc ON f.`film_id`= fc.`film_id`;
-- 查询2:找出类别名字为action的类别id
SELECT c.`category_id` FROM category c WHERE c.`name`="Action"
-- 查询3:融合上述查询,条件就是id相同,即action类别对应的id
SELECT
fc.title, fc.description
FROM
(SELECT f.`title`, f.`description`, fc.`category_id` FROM film AS f JOIN film_category fc ON f.`film_id`= fc.`film_id`) AS fc,
(SELECT c.`category_id` FROM category c WHERE c.`name`="Action") AS c
WHERE
fc.category_id = c.category_id;
SQL32
将employees表的所有员工的last_name和first_name拼接起来作为Name,中间以一个空格区分
-- sqllite,字符串拼接为 || 符号,不支持concat函数,mysql支持concat函数
SELECT
e.`last_name` || " " || e.`first_name`
FROM
employees e;
SQL33
创建一个actor表,包含如下列信息
CREATE TABLE actor(
actor_id smallint(5) NOT NULL,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')), -- 这里不多加个括号无法通过
PRIMARY KEY (actor_id)
)
SQL34
批量插入数据
INSERT INTO actor (actor_id, first_name, last_name, last_update)
VALUES (1, "PENELOPE", "GUINESS", "2006-02-15 12:34:33"),
(2, "NICK", "WAHLBERG", "2006-02-15 12:34:33");
SQL35
批量插入数据,如果数据已经存在,请忽略,不使用replace操作
insert or ignore into actor
values(3,'ED','CHASE','2006-02-15 12:34:33');
SQL36
创建一个actor_name表,将actor表中的所有first_name以及last_name导入改表
create table if not exists actor_name
as select first_name, last_name from actor;
SQL37
对first_name创建唯一索引uniq_idx_firstname,对last_name创建普通索引idx_lastname
-- 创建唯一索引
CREATE UNIQUE INDEX uniq_idx_firstname ON actor(first_name);
-- 创建普通索引
CREATE INDEX idx_lastname ON actor(last_name);
SQL38
针对actor表创建视图actor_name_view
CREATE VIEW actor_name_view(first_name_v, last_name_v)
AS SELECT a.first_name, a.last_name FROM actor a;
SQL39
针对上面的salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005,
-- SQLite中,使用 INDEXED BY 语句进行强制索引查询
SELECT * FROM salaries INDEXED BY idx_emp_no WHERE emp_no=10005;
-- MySQL中,使用 FORCE INDEX 语句进行强制索引查询,可参考:
SELECT * FROM salaries FORCE INDEX idx_emp_no WHERE emp_no = 10005
SQL40
在last_update后面新增加一列名字为create_date
ALTER TABLE actor ADD create_date datetime NOT NULL DEFAULT '0000-00-00 00:00:00';
SQL41
构造一个触发器audit_log,在向employees表中插入一条数据的时候,触发插入相关的数据到audit中
CREATE TRIGGER
audit_log
AFTER INSERT
ON
employees_test
BEGIN
INSERT INTO audit (EMP_no, NAME) VALUES (new.id, new.name);
END;
SQL42
删除emp_no重复的记录,只保留最小的id对应的记录。
-- 第一步:找最小的id记录
SELECT
MIN(t.id) AS id
FROM
titles_test t
GROUP BY
t.emp_no;
-- 第二步:进行删除
DELETE FROM
titles_test
WHERE
titles_test.id
NOT IN (
SELECT
tab.id
FROM (SELECT MIN(t.id) AS id FROM titles_test t GROUP BY t.emp_no) AS tab
); -- 这里的手法!
SQL43
将所有to_date为9999-01-01的全部更新为NULL,且
UPDATE
titles_test
SET
from_date = '2001-01-01', to_date=NULL
WHERE
to_date='9999-01-01';
SQL44
将id=5以及emp_no=10001的行数据替换成id=5以及emp_no=10005,其他数据保持不变,使用replace实现。
replace into titles_test select 5, 10005, title, from_date, to_date FROM titles_test WHERE id=5;
SQL45
将titles_test表名修改为titles_2017
-- mysql 可以
RENAME table titles_test TO titles_2017;
-- 在sqllite中
alter table titles_test rename to titles_2017;
SQL46
在audit表上创建外键约束,其emp_no对应employees_test表的主键id
-- SQLite只能首先删除表,然后再新建表的时候添外键约束。
DROP TABLE audit;
CREATE TABLE audit(
EMP_no INT NOT NULL,
create_date datetime NOT NULL,
FOREIGN KEY(EMP_no) REFERENCES employees_test(ID)
);
-- mysql实现
ALTER TABLE audit ADD FOREIGN KEY (emp_no) REFERENCES employees_test (id);
SQL48
将所有获取奖金的员工当前的薪水增加10%
UPDATE salaries SET salary=(salary*1.1)
WHERE
emp_no IN (SELECT emp_no FROM emp_bonus) AND to_date='9999-01-01';
SQL50
将employees表中的所有员工的last_name和first_name通过(')连接起来。
-- SQLite数据库中,只支持用连接符号"||"来连接字符串,不支持用函数连接
SELECT
last_name || "'" ||first_name AS NAME
FROM
employees;
-- mysql库函数:最外层的两个单引号表示字符串,从左往右数第二个是转义符,第三个是题目需要拼接的单引号
select
concat(last_name, '''', first_name) as name
from
employees;
SQL51
查找字符串'10,A,B' 中逗号','出现的次数cnt。
-- 技巧题,先用任意两个字符替换, 然后计算长度 最后相减
SELECT (LENGTH(REPLACE('10,A,B', ',', '--')) - LENGTH('10,A,B')) AS cnt;
SQL52
获取Employees中的first_name,查询按照first_name最后两个字母,按照升序进行排列
-- mysql 方式
SELECT
first_name
FROM
employees
ORDER BY
RIGHT(first_name, 2);
-- SQLite
SELECT
first_name
FROM
employees
ORDER BY
SUBSTR(first_name, -2, 2);
SQL53
按照dept_no进行汇总,属于同一个部门的emp_no按照逗号进行连接,结果给出dept_no以及连接出的结果employees
-- GROUP_CONCAT 实现分组聚合
SELECT
dept_no, GROUP_CONCAT(emp_no)
FROM
dept_emp
GROUP BY
dept_no;
SQL54
查找排除当前最大、最小salary之后的员工的平均工资avg_salary
-- 第一步:找最大最小工资
SELECT
MAX(salary) max_s, MIN(salary)
AS
min_s
FROM
salaries
WHERE
to_date = '9999-01-01';
-- 第二步:排除了之后的平均工资
SELECT
AVG(s.salary) AS avg_salary
FROM
salaries s,
(SELECT MAX(salary) max_s, MIN(salary) AS min_s FROM salaries WHERE to_date = '9999-01-01') mm
WHERE
s.to_date = '9999-01-01' AND s.`salary`!=mm.max_s AND s.`salary`!=min_s;
SQL55
分页查询employees表,每5行一页,返回第2页的数据
SELECT
*
FROM
employees
LIMIT 5,5; -- 从第5条数据开始的后5条数据
SQL57
使用含有关键字exists查找未分配具体部门的员工的所有信息。
-- 用exists关键字
SELECT
*
FROM
employees e
WHERE NOT EXISTS
(SELECT emp_no FROM dept_emp de WHERE e.`emp_no` = de.`emp_no`);
-- 用not in也可以实现
SELECT
*
FROM
employees e
WHERE
e.`emp_no` NOT IN (SELECT emp_no FROM dept_emp);
SQL59
获取有奖金的员工相关信息
SELECT
e.`emp_no`, e.`first_name`, e.`last_name`, eb.`btype`, s.`salary`, (s.`salary`*eb.`btype` / 10.0) AS bonus
FROM
emp_bonus eb
JOIN
employees e
ON
eb.`emp_no` = e.`emp_no`
JOIN
salaries s
ON
eb.`emp_no` = s.`emp_no`
WHERE
s.`to_date`='9999-01-01';
SQL60
统计salary的累计和running_total
SELECT
s1.`emp_no`, s1.`salary`, SUM(s2.`salary`)
FROM
salaries s1,
salaries s2
WHERE
s1.`emp_no` >= s2.`emp_no`
AND s1.to_date = '9999-01-01'
AND s2.to_date = '9999-01-01'
GROUP BY s1.`emp_no`;
SQL61
对于employees表中,给出奇数行的first_name
SELECT
e1.`first_name`
FROM
employees e1
WHERE
(SELECT COUNT(*) FROM employees e2 WHERE e1.`first_name` >= e2.`first_name`) % 2 =1;
SQL62
出现三次以上相同积分的情况
select
number
from
grade
group by
number
having
count(number) >=3;
SQL63
刷题通过的题目排名
select
pn1.id, pn1.number, count(distinct(pn2.number)) as rank
from
passing_number pn1,
passing_number pn2
where
pn1.number <= pn2.number
group by
pn1.id
order by
pn1.number desc, pn1.id asc;
SQL64
找到每个人的任务
select
p.id, p.name, t.content
from
person p
left join
task t
on
p.id = t.person_id
order by
p.id asc;
SQL65
异常的邮件概率
-- 进行计算
select
-- 后续的概率计算
-- 1. round 四舍五入函数,保留3位小数
-- 2. sum 计算失败的次数,用了case语句
-- 3. count 计算总的发送次数,通过主键id计算
e.date, round(sum(case e.type when 'completed' then 0 else 1 end) * 1.0 / count(e.id), 3) as p
from
email e, -- 邮件表
(select id from user where is_blacklist=1) ub -- 黑名单用户
where
-- 条件:
-- 1.发送者不是黑名单
-- 2.接受者也不再黑名单中
e.send_id not in (ub.id) and e.receive_id not in (ub.id)
group by
e.date -- 按照日期进行分组
order by
e.date; -- 按照日期进行排序
SQL67
牛客每个人最近的登录日期(一)
select
max(date) as d
from
login
group by
user_id
order by
user_id;
SQL68
牛客每个人最近的登录日期(二)
select
u.name as u_n, c.name as c_n, max(l.date)
from
login l
join
user u
on
l.user_id = u.id
join
client c
on
l.client_id = c.id
group by
l.user_id
order by
u.name;
SQL69
牛客每个人最近的登录日期(三)
-- 第一次登陆的时间
SELECT
user_id, MIN(DATE) AS first_login
FROM
login
GROUP BY
user_id;
-- 总人数计算
SELECT COUNT(DISTINCT user_id) FROM login;
-- 结合一下
SELECT
ROUND(COUNT(*)*1.0 / (SELECT COUNT(DISTINCT user_id) FROM login), 3)
FROM
login l
JOIN
(SELECT
user_id, MIN(DATE) AS first_login
FROM
login
GROUP BY
user_id) AS fl
ON
l.user_id = fl.user_id AND l.date != fl.first_login
WHERE
date(fl.first_login, '+1 day')=l.date; -- 这里筛选了满足第一天登陆后第二天也登陆的记录
SQL70
牛客每个人最近的登录日期(四)
-- 第一步:总共有几天
SELECT
DISTINCT(DATE)
FROM
login;
-- 第二步:找出用户第一次登录日期
SELECT
user_id, MIN(DATE) AS first_date
FROM
login
GROUP BY
user_id;
-- 结合上述两步
SELECT
l1.real_date, IFNULL(COUNT(l2.user_id), 0) -- count就计算新用户数
FROM
(SELECT
DISTINCT(DATE) AS real_date
FROM
login) AS l1 -- 天数表
LEFT JOIN
(SELECT
user_id, MIN(DATE) AS first_date
FROM
login
GROUP BY
user_id) AS l2 -- 新用户登录表
ON
l1.real_date = l2.first_date -- 合并的条件就是日期相同
GROUP BY
l1.real_date
SQL71
牛客每个人最近的登录日期(五)
SELECT
tab1.real_date as date, ROUND(IFNULL(IFNULL(tab2.last_num, 0) * 1.0 / IFNULL(tab1.all_num, 0), 0), 3) AS p
FROM
(SELECT
l1.real_date, IFNULL(COUNT(l2.user_id), 0) AS all_num
FROM
(SELECT
DISTINCT(DATE) AS real_date
FROM
login) AS l1 -- 总天数表
LEFT JOIN
(SELECT
user_id, MIN(DATE) AS first_date
FROM
login
GROUP BY
user_id) AS l2 -- 用户最早登陆表
ON
l1.real_date = l2.first_date
GROUP BY
l1.real_date) tab1 -- 记录了该天所有新用户登陆的数据
LEFT JOIN
(SELECT
l1.date, COUNT(l1.user_id) AS last_num
FROM
login l1
JOIN
(SELECT
user_id, MIN(DATE) AS first_date
FROM
login
GROUP BY
user_id) AS l2 -- 用户最早登陆表
ON
l1.user_id = l2.user_id AND l1.date != l2.first_date
WHERE
date(l2.first_date, '+1 day')=l1.date
GROUP BY
l1.date) tab2 -- tab2 记录了满足第一天登陆后第二天也登陆的用户
ON
date(tab1.real_date, '+1 day') = tab2.date;
SQL72
牛客每个人最近的登录日期(六)
-- 关键在此!
SELECT
pn1.user_id, SUM(pn2.number) AS nums, pn1.date AS DATE
FROM
passing_number pn1,
passing_number pn2
WHERE
pn1.user_id = pn2.user_id
AND pn1.date >= pn2.date
GROUP BY
pn1.user_id, pn1.date;
-- 根据上面的表去匹配其他信息
SELECT
u.name AS u_n, c.name AS c_n, tb.date AS DATE, tb.nums AS ps_num
FROM
(SELECT
pn1.user_id, SUM(pn2.number) AS nums, pn1.date AS DATE
FROM
passing_number pn1,
passing_number pn2
WHERE
pn1.user_id = pn2.user_id
AND pn1.date >= pn2.date
GROUP BY
pn1.user_id, pn1.date) AS tb
JOIN
login l
ON
tb.user_id = l.user_id AND tb.date = l.date
JOIN
USER u
ON
tb.user_id = u.id
JOIN
CLIENT c
ON
l.client_id = c.id
ORDER BY
tb.date ASC, u.name ASC;
SQL72
考试分数(一)
select
job, round(avg(score), 3) as score
from
grade
group by
job
order by
score desc;
SQL73
考试分数(二)
-- 第一步:找出平均成绩
select
job, avg(score)
from
grade
group by
score;
-- 第二步:找出大于平均分数的数据
SELECT
g1.id, g1.job, g1.score AS score
FROM
grade g1
LEFT JOIN
(SELECT
job, AVG(score) AS avg_score
FROM
grade
GROUP BY
job) AS g2
ON
g1.job = g2.job
WHERE
g1.score > g2.avg_score;
SQL74
考试分数(三)
-- 合并一下score表和language表
SELECT
g.id AS id,
l.name AS NAME,
g.score AS score,
dense_rank() over (PARTITION BY g.language_id ORDER BY g.score DESC) AS score_order -- 窗口函数:序号函数,用于并列排序的
FROM
grade g
JOIN
LANGUAGE l
ON
g.language_id = l.id;
-- 根据上表给出结果
SELECT
t.id, t.name, t.score
FROM
(SELECT
g.id AS id, l.name AS NAME, g.score AS score, dense_rank() over (PARTITION BY g.language_id ORDER BY g.score DESC) AS score_order
FROM
grade g
JOIN
LANGUAGE l
ON
g.language_id = l.id) t
WHERE
t.score_order <=2 -- 在经过窗口函数排序之后的结果
ORDER BY
t.name, t.score DESC, t.id;
SQL75
考试分数(四)
-- 表1:使用窗口函数按照job分组对成绩进行降序排序
SELECT
*,
-- 窗口函数:用于顺序排序,并列的时候也是顺序排序
row_number() over (PARTITION BY job ORDER BY score DESC) AS score_order
FROM
grade;
-- 表2:按照job进行分组,计算每个job中中间记录数,奇数时就是一个值,偶数是为.5小数
SELECT
job,
(COUNT(*)+1)*1.0/2 AS middle
FROM
grade
GROUP BY
job;
-- 对表1和表2进行合并,给出最终结果
SELECT
t1.job,
cast(t2.middle as integer) AS START, -- 奇/偶都一样,即向下取整
(CASE (t2.middle-cast(t2.middle as integer)) WHEN 0 THEN cast(t2.middle as integer) ELSE cast(t2.middle as integer)+1 END) AS END
-- 上述对奇/偶进行区别,通过case when ...then ...else ..end
FROM
(SELECT
*, row_number() over (PARTITION BY job ORDER BY score DESC) AS score_order
FROM
grade) AS t1,
(SELECT job, (COUNT(*)+1)*1.0/2 AS middle FROM grade GROUP BY job) AS t2
WHERE
t1.job = t2.job
GROUP BY
t1.job;
SQL76
考试分数(五)
-- 表1:使用窗口函数按照job分组对成绩进行降序排序
SELECT
*,
row_number() over (PARTITION BY job ORDER BY score DESC) AS score_order
FROM
grade;
-- 表2:确定每个job中间的人数,奇数为1,偶数为2
SELECT
job,
cast((COUNT(id)+1)/2 as integer) AS START,
(cast((COUNT(id)+1)/2 as integer) + (CASE COUNT(*)%2=1 WHEN 1 THEN 0 ELSE 1 END)) AS END
FROM
grade
GROUP BY
job;
-- 进行合并
SELECT
t1.id, t1.job, t1.score, t1.score_order
FROM
(SELECT
*, row_number() over (PARTITION BY job ORDER BY score DESC) AS score_order
FROM
grade) AS t1
JOIN
(SELECT
job,
cast((COUNT(id)+1)/2 as integer) AS START,
(cast((COUNT(id)+1)/2 as integer) + (CASE COUNT(*)%2=1 WHEN 1 THEN 0 ELSE 1 END)) AS END
FROM
grade
GROUP BY
job) AS t2
ON
-- 合并条件:
-- 1. job相同
-- 2. 分数的排序为中间的值
t1.job = t2.job AND (t1.score_order = t2.START OR t1.score_order = t2.END)
ORDER BY t1.id;
MySQL:怒刷牛客网“sql实战”的更多相关文章
- 牛客网sql实战参考答案(mysql版):1-15
1.查找最晚入职员工的所有信息,为了减轻入门难度,目前所有的数据里员工入职的日期都不是同一天(sqlite里面的注释为--,mysql为comment) CREATE TABLE `employees ...
- 牛客网sql实战参考答案(mysql版):16-21
16.统计出当前(titles.to_date='9999-01-01')各个title类型对应的员工当前(salaries.to_date='9999-01-01')薪水对应的平均工资.结果给出ti ...
- MySql面试题、知识汇总、牛客网SQL专题练习
点击名字直接跳转到链接: Linux运维必会的100道MySql面试题之(一) Linux运维必会的100道MySql面试题之(二) Linux运维必会的100道MySql面试题之(三) Linux运 ...
- 牛客网Sql
牛客网Sql: 1.查询最晚入职的员工信息 select * from employees where hire_date =(select max(hire_date) from employee ...
- 牛客网sql刷题解析-完结
查找最晚入职员工的所有信息 解题步骤: 题目:查询最晚入职员工的所有信息 目标:查询员工的所有信息 筛选条件:最晚入职 答案: SELECT *--查询所有信息就用* ...
- 牛客-数据库SQL实战
查找最晚入职员工的所有信息 CREATE TABLE `employees` ( `emp_no` ) NOT NULL, `birth_date` date NOT NULL, `first_nam ...
- 牛客网sql练习
一建表语句 /* Navicat MySQL Data Transfer Source Server : test Source Server Version : 50717 Source Host ...
- 牛客网数据库SQL实战解析(41-50题)
牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0 牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010 ...
- 牛客网数据库SQL实战解析(31-40题)
牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0 牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010 ...
随机推荐
- 《通过刷leetcode学习Go语言》之(1):序言
Author : Email : vip_13031075266@163.com Date : 2021.03.07 Version : 北京 C ...
- ByteArrayOutputStream小测试
import java.io.*; import org.junit.Test; public class ByteArrayOutputStreamTest { @Test public void ...
- 升级到windows10之后的骚操作,安装debian,centos7,支持linux、docker、kubectl命令
修改Windows10默认字体和图标很大 打开Hyper-V Windows10下载Docker Desktop https://www.docker.com/products/docker-desk ...
- Nginx:进程调度
Blog:博客园 个人 Nginx采用的是固定数量的多进程模型,由一个主进程(MasterProcess)和数量与主机CPU核数相同的工作进程协同处理各种事件. 主管理进程负责工作进程的配置加载.启停 ...
- PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句
对于 MySQLi 来说,事务和预处理语句当然是它之所以能够淘汰 MySQL(原始) 扩展的资本.我们之前也已经学习过了 PDO 中关于事务和预处理语句相关的内容.所以在这里,我们就不再多讲理论方面的 ...
- Docker DevOps实战:Docker+Jenkins+Python+Pytest+Allure(1)- 创建Jenkins容器、安装Python环境、安装项目依赖类库、安装Allure报告插件
前言: 本文实操笔记参照菠萝笔记,安装过程中的坑大家可以参考下 创建Jenkins容器 # 下载Jenkins镜像 [root@localhost ~]# docker pull jenkins/je ...
- ubuntu系统安装docker
系统版本:Ubuntu 18.04 # 更新apt update # 安装依赖apt install apt-transport-https ca-certificates curl software ...
- javascript DOM 共同父节点
* 查找两个节点的最近的一个共同父节点,可以包括节点自身 input: oNode1 和 oNode2 在同一文档中,且不会为相同的节点 function commonParentNode(oNode ...
- Centos7安装配置Gitlab-CE
GitLab介绍 GitLab:是一个基于Git实现的在线代码仓库托管软件,你可以用gitlab自己搭建一个类似于Github一样的系统,一般用于在企业.学校等内部网络搭建git私服. 功能:Gitl ...
- fiddler抓包工具 https抓取 ios手机端抓取
fiddler抓包工具 https抓取 ios手机端抓取 转载链接:https://www.cnblogs.com/bais/p/9118297.html 抓取pc端https请求,ios手机端 ...