题目选自leetcode 上的题库
可能不一定都是最优解,答案仅供参考
每道题后面都应相应的难度等级,如果没时间做的话 可以在leetcode 按出题频率刷题
祝大家面试取得好的成绩
585. 2016年的投资
难度中等14收藏分享切换为英文关注反馈
SQL架构
写一个查询语句,将 2016 年 (TIV_2016) 所有成功投资的金额加起来,保留 2 位小数。
对于一个投保人,他在 2016 年成功投资的条件是:
- 他在 2015 年的投保额 (TIV_2015) 至少跟一个其他投保人在 2015 年的投保额相同。
- 他所在的城市必须与其他投保人都不同(也就是说维度和经度不能跟其他任何一个投保人完全相同)。
输入格式:
表 *insurance* 格式如下:
Column Name | Type |
---|---|
PID | INTEGER(11) |
TIV_2015 | NUMERIC(15,2) |
TIV_2016 | NUMERIC(15,2) |
LAT | NUMERIC(5,2) |
LON | NUMERIC(5,2) |
PID 字段是投保人的投保编号, TIV_2015 是该投保人在2015年的总投保金额, TIV_2016 是该投保人在2016年的投保金额, LAT 是投保人所在城市的维度, LON 是投保人所在城市的经度。
样例输入
PID | TIV_2015 | TIV_2016 | LAT | LON |
---|---|---|---|---|
1 | 10 | 5 | 10 | 10 |
2 | 20 | 20 | 20 | 20 |
3 | 10 | 30 | 20 | 20 |
4 | 10 | 40 | 40 | 40 |
样例输出
TIV_2016 |
---|
45.00 |
解释
就如最后一个投保人,第一个投保人同时满足两个条件:
1. 他在 2015 年的投保金额 TIV_2015 为 '10' ,与第三个和第四个投保人在 2015 年的投保金额相同。
2. 他所在城市的经纬度是独一无二的。
第二个投保人两个条件都不满足。他在 2015 年的投资 TIV_2015 与其他任何投保人都不相同。
且他所在城市的经纬度与第三个投保人相同。基于同样的原因,第三个投保人投资失败。
所以返回的结果是第一个投保人和最后一个投保人的 TIV_2016 之和,结果是 45 。
select sum(TIV_2016) TIV_2016
from (
select PID,TIV_2016,cnt,
count(*) over(partition by loc ) lcnt
from (
select PID,TIV_2016,
count(TIV_2015) over(partition by TIV_2015 ) cnt,
concat_ws(",",LAT,LON) loc
from insurance
)t1
)t2
where lcnt=1 and cnt!=1
注意去重顺序 不要先对TIV_2015去重 不然 local去重时会丢失数据
优化 窗口
SELECT
ROUND(SUM(TIV_2016), 2) as TIV_2016
FROM(
SELECT
*,
count(*) over(partition by TIV_2015) as cnt_1,
count(*) over(partition by LAT, LON) as cnt_2
FROM
insurance
) a
WHERE a.cnt_1 > 1 AND a.cnt_2 < 2
586. 订单最多的客户
难度简单
SQL架构
在表 orders 中找到订单数最多客户对应的 customer_number 。
数据保证订单数最多的顾客恰好只有一位。
表 *orders* 定义如下:
Column | Type |
---|---|
order_number (PK) | int |
customer_number | int |
order_date | date |
required_date | date |
shipped_date | date |
status | char(15) |
comment | char(200) |
样例输入
order_number | customer_number | order_date | required_date | shipped_date | status | comment |
---|---|---|---|---|---|---|
1 | 1 | 2017-04-09 | 2017-04-13 | 2017-04-12 | Closed | |
2 | 2 | 2017-04-15 | 2017-04-20 | 2017-04-18 | Closed | |
3 | 3 | 2017-04-16 | 2017-04-25 | 2017-04-20 | Closed | |
4 | 3 | 2017-04-18 | 2017-04-28 | 2017-04-25 | Closed |
样例输出
customer_number |
---|
3 |
解释
customer_number 为 '3' 的顾客有两个订单,比顾客 '1' 或者 '2' 都要多,因为他们只有一个订单
所以结果是该顾客的 customer_number ,也就是 3 。
进阶: 如果有多位顾客订单数并列最多,你能找到他们所有的 customer_number 吗?
select customer_number
from orders
group by customer_number
order by count(*) desc
limit 1
如果 数据量很大 order by 不太好
595. 大的国家
难度简单
SQL架构
这里有张 World
表
+-----------------+------------+------------+--------------+---------------+
| name | continent | area | population | gdp |
+-----------------+------------+------------+--------------+---------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000 |
| Albania | Europe | 28748 | 2831741 | 12960000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000 |
| Andorra | Europe | 468 | 78115 | 3712000 |
| Angola | Africa | 1246700 | 20609294 | 100990000 |
+-----------------+------------+------------+--------------+---------------+
如果一个国家的面积超过300万平方公里,或者人口超过2500万,那么这个国家就是大国家。
编写一个SQL查询,输出表中所有大国家的名称、人口和面积。
例如,根据上表,我们应该输出:
+--------------+-------------+--------------+
| name | population | area |
+--------------+-------------+--------------+
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
+--------------+-------------+--------------+
select name ,population,area
from World
where area >3000000 or population >25000000
596. 超过5名学生的课
难度简单
SQL架构
有一个courses
表 ,有: student (学生) 和 class (课程)。
请列出所有超过或等于5名学生的课。
例如,表:
+---------+------------+
| student | class |
+---------+------------+
| A | Math |
| B | English |
| C | Math |
| D | Biology |
| E | Math |
| F | Computer |
| G | Math |
| H | Math |
| I | Math |
+---------+------------+
应该输出:
+---------+
| class |
+---------+
| Math |
+---------+
Note:
学生在每个课中不应被重复计算。
select class
from courses
group by class
having count(distinct student)>=5
一个学生可能多次选课。。记得distinct
597. 好友申请 I :总体通过率
难度简单21收藏分享切换为英文关注反馈
SQL架构
在 Facebook 或者 Twitter 这样的社交应用中,人们经常会发好友申请也会收到其他人的好友申请。现在给如下两个表:
表: friend_request
sender_id | send_to_id | request_date |
---|---|---|
1 | 2 | 2016_06-01 |
1 | 3 | 2016_06-01 |
1 | 4 | 2016_06-01 |
2 | 3 | 2016_06-02 |
3 | 4 | 2016-06-09 |
表: request_accepted
requester_id | accepter_id | accept_date |
---|---|---|
1 | 2 | 2016_06-03 |
1 | 3 | 2016-06-08 |
2 | 3 | 2016-06-08 |
3 | 4 | 2016-06-09 |
3 | 4 | 2016-06-10 |
写一个查询语句,求出好友申请的通过率,用 2 位小数表示。通过率由接受好友申请的数目除以申请总数。
对于上面的样例数据,你的查询语句应该返回如下结果。
accept_rate |
---|
0.80 |
注意:
通过的好友申请不一定都在表 friend_request 中。在这种情况下,你只需要统计总的被通过的申请数(不管它们在不在原来的申请中),并将它除以申请总数,得到通过率
一个好友申请发送者有可能会给接受者发几条好友申请,也有可能一个好友申请会被通过好几次。这种情况下,重复的好友申请只统计一次。
如果一个好友申请都没有,通过率为 0.00 。
解释: 总共有 5 个申请,其中 4 个是不重复且被通过的好友申请,所以成功率是 0.80 。
进阶:
你能写一个查询语句得到每个月的通过率吗?
你能求出每一天的累计通过率吗?
select
round(
ifnull(
(select count(*) from (select distinct requester_id, accepter_id from request_accepted) as A)
/
(select count(*) from (select distinct sender_id, send_to_id from friend_request) as B),
0)
, 2) as accept_rate;
601. 体育馆的人流量
难度困难113收藏分享切换为英文关注反馈
SQL架构
X 市建了一个新的体育馆,每日人流量信息被记录在这三列信息中:序号 (id)、日期 (visit_date)、 人流量 (people)。
请编写一个查询语句,找出人流量的高峰期。高峰期时,至少连续三行记录中的人流量不少于100。
例如,表 stadium
:
+------+------------+-----------+
| id | visit_date | people |
+------+------------+-----------+
| 1 | 2017-01-01 | 10 |
| 2 | 2017-01-02 | 109 |
| 3 | 2017-01-03 | 150 |
| 4 | 2017-01-04 | 99 |
| 5 | 2017-01-05 | 145 |
| 6 | 2017-01-06 | 1455 |
| 7 | 2017-01-07 | 199 |
| 8 | 2017-01-08 | 188 |
+------+------------+-----------+
对于上面的示例数据,输出为:
+------+------------+-----------+
| id | visit_date | people |
+------+------------+-----------+
| 5 | 2017-01-05 | 145 |
| 6 | 2017-01-06 | 1455 |
| 7 | 2017-01-07 | 199 |
| 8 | 2017-01-08 | 188 |
+------+------------+-----------+
提示:
每天只有一行记录,日期随着 id 的增加而增加。
3表相连(244 ms)
select distinct t1.*
from stadium t1, stadium t2, stadium t3
where t1.people >= 100 and t2.people >= 100 and t3.people >= 100
and
(
(t1.id - t2.id = 1 and t1.id - t3.id = 2 and t2.id - t3.id =1) -- t1, t2, t3
or
(t2.id - t1.id = 1 and t2.id - t3.id = 2 and t1.id - t3.id =1) -- t2, t1, t3
or
(t3.id - t2.id = 1 and t2.id - t1.id =1 and t3.id - t1.id = 2) -- t3, t2, t1
)
order by t1.id
窗口函数(272 ms)
select id,visit_date,people from
(
select id
,lead(people,1) over(order by id) ld
,lead(people,2) over(order by id) ld2
,visit_date
,lag(people,1) over(order by id) lg
,lag(people,2) over(order by id) lg2
,people
from stadium
) a
where (a.ld>=100 and a.lg>=100 and a.people>=100)
or (a.ld>=100 and a.ld2>=100 and a.people>=100)
or (a.lg>=100 and a.lg2>=100 and a.people>=100)
602. 好友申请 II :谁有最多的好友
难度中等
SQL架构
在 Facebook 或者 Twitter 这样的社交应用中,人们经常会发好友申请也会收到其他人的好友申请。
表 request_accepted
存储了所有好友申请通过的数据记录,其中, requester_id 和 accepter_id 都是用户的编号。
requester_id | accepter_id | accept_date |
---|---|---|
1 | 2 | 2016_06-03 |
1 | 3 | 2016-06-08 |
2 | 3 | 2016-06-08 |
3 | 4 | 2016-06-09 |
写一个查询语句,求出谁拥有最多的好友和他拥有的好友数目。对于上面的样例数据,结果为:
id | num |
---|---|
3 | 3 |
注意:
- 保证拥有最多好友数目的只有 1 个人。
- 好友申请只会被接受一次,所以不会有 requester_id 和 accepter_id 值都相同的重复记录。
解释:
编号为 '3' 的人是编号为 '1','2' 和 '4' 的好友,所以他总共有 3 个好友,比其他人都多。
进阶:
在真实世界里,可能会有多个人拥有好友数相同且最多,你能找到所有这些人吗?
select rid as `id`,count(aid) as `num`
from
(
select R1.requester_id as rid,R1.accepter_id as aid
from request_accepted as R1
UNION all
select R2.accepter_id as rid,R2.requester_id as aid
from request_accepted as R2
) as A
group by rid
order by num desc
limit 0,1
603. 连续空余座位
难度简单
SQL架构
几个朋友来到电影院的售票处,准备预约连续空余座位。
你能利用表 cinema
,帮他们写一个查询语句,获取所有空余座位,并将它们按照 seat_id 排序后返回吗?
seat_id | free |
---|---|
1 | 1 |
2 | 0 |
3 | 1 |
4 | 1 |
5 | 1 |
对于如上样例,你的查询语句应该返回如下结果。
seat_id |
---|
3 |
4 |
5 |
注意:
- seat_id 字段是一个自增的整数,free 字段是布尔类型('1' 表示空余, '0' 表示已被占据)。
- 连续空余座位的定义是大于等于 2 个连续空余的座位。
select seat_id
from (
select seat_id,
lag(seat_id,1,-99) over(order by seat_id) ls,
lead(seat_id,1,-99) over(order by seat_id) rs
from cinema
where free=1
)t1
where seat_id-ls = 1 or rs-seat_id =1
607. 销售员
难度简单
SQL架构
描述
给定 3 个表: salesperson
, company
, orders
。
输出所有表 salesperson
中,没有向公司 'RED' 销售任何东西的销售员。
示例:
输入
表: salesperson
+----------+------+--------+-----------------+-----------+
| sales_id | name | salary | commission_rate | hire_date |
+----------+------+--------+-----------------+-----------+
| 1 | John | 100000 | 6 | 4/1/2006 |
| 2 | Amy | 120000 | 5 | 5/1/2010 |
| 3 | Mark | 65000 | 12 | 12/25/2008|
| 4 | Pam | 25000 | 25 | 1/1/2005 |
| 5 | Alex | 50000 | 10 | 2/3/2007 |
+----------+------+--------+-----------------+-----------+
表 salesperson
存储了所有销售员的信息。每个销售员都有一个销售员编号 sales_id 和他的名字 name 。
表: company
+---------+--------+------------+
| com_id | name | city |
+---------+--------+------------+
| 1 | RED | Boston |
| 2 | ORANGE | New York |
| 3 | YELLOW | Boston |
| 4 | GREEN | Austin |
+---------+--------+------------+
表 company
存储了所有公司的信息。每个公司都有一个公司编号 com_id 和它的名字 name 。
表: orders
+----------+------------+---------+----------+--------+
| order_id | order_date | com_id | sales_id | amount |
+----------+------------+---------+----------+--------+
| 1 | 1/1/2014 | 3 | 4 | 100000 |
| 2 | 2/1/2014 | 4 | 5 | 5000 |
| 3 | 3/1/2014 | 1 | 1 | 50000 |
| 4 | 4/1/2014 | 1 | 4 | 25000 |
+----------+----------+---------+----------+--------+
表 orders
存储了所有的销售数据,包括销售员编号 sales_id 和公司编号 com_id 。
输出
+------+
| name |
+------+
| Amy |
| Mark |
| Alex |
+------+
解释
根据表 orders
中的订单 '3' 和 '4' ,容易看出只有 'John' 和 'Pam' 两个销售员曾经向公司 'RED' 销售过。
所以我们需要输出表 salesperson
中所有其他人的名字。\
select name
from salesperson
where sales_id not in
(
select sales_id
from orders
where com_id =
(
select com_id
from company
where name ='RED'
)
)
608. 树节点
难度中等
SQL架构
给定一个表 tree
,id 是树节点的编号, p_id 是它父节点的 id 。
+----+------+
| id | p_id |
+----+------+
| 1 | null |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
+----+------+
树中每个节点属于以下三种类型之一:
- 叶子:如果这个节点没有任何孩子节点。
- 根:如果这个节点是整棵树的根,即没有父节点。
- 内部节点:如果这个节点既不是叶子节点也不是根节点。
写一个查询语句,输出所有节点的编号和节点的类型,并将结果按照节点编号排序。上面样例的结果为:
+----+------+
| id | Type |
+----+------+
| 1 | Root |
| 2 | Inner|
| 3 | Leaf |
| 4 | Leaf |
| 5 | Leaf |
+----+------+
解释
节点 '1' 是根节点,因为它的父节点是 NULL ,同时它有孩子节点 '2' 和 '3' 。
节点 '2' 是内部节点,因为它有父节点 '1' ,也有孩子节点 '4' 和 '5' 。
节点 '3', '4' 和 '5' 都是叶子节点,因为它们都有父节点同时没有孩子节点。
-
样例中树的形态如下:
1 / \ 2 3 / \ 4 5
注意
如果树中只有一个节点,你只需要输出它的根属性。
select id,
(case when p_id is null then "Root"
when id not in (select ifnull(p_id,0) from tree) then "Leaf"
else "Inner" end) Type
from tree
610. 判断三角形
难度简单
SQL架构
一个小学生 Tim 的作业是判断三条线段是否能形成一个三角形。
然而,这个作业非常繁重,因为有几百组线段需要判断。
假设表 triangle
保存了所有三条线段的三元组 x, y, z ,你能帮 Tim 写一个查询语句,来判断每个三元组是否可以组成一个三角形吗?
x | y | z |
---|---|---|
13 | 15 | 30 |
10 | 20 | 15 |
对于如上样例数据,你的查询语句应该返回如下结果:
x | y | z | triangle |
---|---|---|---|
13 | 15 | 30 | No |
10 | 20 | 15 | Yes |
select x,y,z,
if(x+y>z && x+z>y && y+z>x,'Yes','No') triangle
from triangle
612. 平面上的最近距离
难度中等
SQL架构
表 point_2d
保存了所有点(多于 2 个点)的坐标 (x,y) ,这些点在平面上两两不重合。
写一个查询语句找到两点之间的最近距离,保留 2 位小数。
x | y |
---|---|
-1 | -1 |
0 | 0 |
-1 | -2 |
最近距离在点 (-1,-1) 和(-1,2) 之间,距离为 1.00 。所以输出应该为:
shortest |
---|
1.00 |
注意:任意点之间的最远距离小于 10000 。
SELECT
ROUND(SQRT(MIN((POW(p1.x - p2.x, 2) + POW(p1.y - p2.y, 2)))), 2) AS shortest
FROM
point_2d p1
JOIN
point_2d p2 ON p1.x != p2.x OR p1.y != p2.y
优化 :减少重复计算
SELECT
ROUND(SQRT(MIN((POW(p1.x - p2.x, 2) + POW(p1.y - p2.y, 2)))),2) AS shortest
FROM
point_2d p1
JOIN
point_2d p2 ON (p1.x <= p2.x AND p1.y < p2.y)
OR (p1.x <= p2.x AND p1.y > p2.y)
OR (p1.x < p2.x AND p1.y = p2.y)
613. 直线上的最近距离
难度简单
SQL架构
表 point
保存了一些点在 x 轴上的坐标,这些坐标都是整数。
写一个查询语句,找到这些点中最近两个点之间的距离。
x |
---|
-1 |
0 |
2 |
最近距离显然是 '1' ,是点 '-1' 和 '0' 之间的距离。所以输出应该如下:
shortest |
---|
1 |
注意:每个点都与其他点坐标不同,表 table
不会有重复坐标出现。
进阶:如果这些点在 x 轴上从左到右都有一个编号,输出结果时需要输出最近点对的编号呢?
开窗方法 178m
select min(l-x) shortest
from(
select x,lead(x,1,null) over(order by x) l
from point
)t1
join方法 268m
SELECT
MIN(ABS(p1.x - p2.x)) AS shortest
FROM
point p1
JOIN
point p2 ON p1.x != p2.x
;
614. 二级关注者
难度中等
SQL架构
在 facebook 中,表 follow
会有 2 个字段: followee, follower ,分别表示被关注者和关注者。
请写一个 sql 查询语句,对每一个关注者,查询关注他的关注者的数目。
比方说:
+-------------+------------+
| followee | follower |
+-------------+------------+
| A | B |
| B | C |
| B | D |
| D | E |
+-------------+------------+
应该输出:
+-------------+------------+
| follower | num |
+-------------+------------+
| B | 2 |
| D | 1 |
+-------------+------------+
解释:
B 和 D 都在在 follower 字段中出现,作为被关注者,B 被 C 和 D 关注,D 被 E 关注。A 不在 follower 字段内,所以A不在输出列表中。
注意:
- 被关注者永远不会被他 / 她自己关注。
- 将结果按照字典序返回。
select followee follower,count(distinct follower) num
from follow
where followee in (
select follower
from follow
group by follower
)
group by followee
order by follower
这里出现了重复关注 ,需要去重
615. 平均工资:部门与公司比较
难度困难
SQL架构
给如下两个表,写一个查询语句,求出在每一个工资发放日,每个部门的平均工资与公司的平均工资的比较结果 (高 / 低 / 相同)。
表: salary
id | employee_id | amount | pay_date |
---|---|---|---|
1 | 1 | 9000 | 2017-03-31 |
2 | 2 | 6000 | 2017-03-31 |
3 | 3 | 10000 | 2017-03-31 |
4 | 1 | 7000 | 2017-02-28 |
5 | 2 | 6000 | 2017-02-28 |
6 | 3 | 8000 | 2017-02-28 |
employee_id 字段是表 employee
中 employee_id 字段的外键。
employee_id | department_id |
---|---|
1 | 1 |
2 | 2 |
3 | 2 |
对于如上样例数据,结果为:
pay_month | department_id | comparison |
---|---|---|
2017-03 | 1 | higher |
2017-03 | 2 | lower |
2017-02 | 1 | same |
2017-02 | 2 | same |
解释
在三月,公司的平均工资是 (9000+6000+10000)/3 = 8333.33...
由于部门 '1' 里只有一个 employee_id 为 '1' 的员工,所以部门 '1' 的平均工资就是此人的工资 9000 。因为 9000 > 8333.33 ,所以比较结果是 'higher'。
第二个部门的平均工资为 employee_id 为 '2' 和 '3' 两个人的平均工资,为 (6000+10000)/2=8000 。因为 8000 < 8333.33 ,所以比较结果是 'lower' 。
在二月用同样的公式求平均工资并比较,比较结果为 'same' ,因为部门 '1' 和部门 '2' 的平均工资与公司的平均工资相同,都是 7000 。
select
pay_month,
department_id,
(case when avgs>ts then 'higher'
when avgs
也可以用if
IF(avgs>ts,'higher',IF(avgs=ts,'same','lower')) AS comparison
618. 学生地理信息报告
难度困难
SQL架构
一所美国大学有来自亚洲、欧洲和美洲的学生,他们的地理信息存放在如下 student
表中。
name | continent |
---|---|
Jack | America |
Pascal | Europe |
Xi | Asia |
Jane | America |
写一个查询语句实现对大洲(continent)列的 透视表 操作,使得每个学生按照姓名的字母顺序依次排列在对应的大洲下面。输出的标题应依次为美洲(America)、亚洲(Asia)和欧洲(Europe)。数据保证来自美洲的学生不少于来自亚洲或者欧洲的学生。
对于样例输入,它的对应输出是:
America | Asia | Europe |
---|---|---|
Jack | Xi | Pascal |
Jane |
进阶:如果不能确定哪个大洲的学生数最多,你可以写出一个查询去生成上述学生报告吗?
开窗
select
max(if(continent='America',name,null)) America,
max(if(continent='Asia',name,null)) Asia,
max(if(continent='Europe',name,null)) Europe
from
(select *, row_number() over(partition by continent order by name) rk
from student) t
group by rk
变量
SELECT
America, Asia, Europe
FROM
(SELECT @as:=0, @am:=0, @eu:=0) t,
(SELECT
@as:=@as + 1 AS asid, name AS Asia
FROM
student
WHERE
continent = 'Asia'
ORDER BY Asia) AS t1
RIGHT JOIN
(SELECT
@am:=@am + 1 AS amid, name AS America
FROM
student
WHERE
continent = 'America'
ORDER BY America) AS t2 ON asid = amid
LEFT JOIN
(SELECT
@eu:=@eu + 1 AS euid, name AS Europe
FROM
student
WHERE
continent = 'Europe'
ORDER BY Europe) AS t3 ON amid = euid
官方给出的。。同下方开窗
select America,Asia,Europe
from(
select row_number() over(order by name) as rn,name as America from student
where continent='America'
) a
left join(
select row_number() over(order by name) as rn,name as Asia from student
where continent='Asia'
) b on a.rn=b.rn
left join(
select row_number() over(order by name) as rn,name as Europe from student
where continent='Europe'
) c on a.rn=c.rn
619. 只出现一次的最大数字
难度简单
SQL架构
表 my_numbers
的 num 字段包含很多数字,其中包括很多重复的数字。
你能写一个 SQL 查询语句,找到只出现过一次的数字中,最大的一个数字吗?
+---+
|num|
+---+
| 8 |
| 8 |
| 3 |
| 3 |
| 1 |
| 4 |
| 5 |
| 6 |
对于上面给出的样例数据,你的查询语句应该返回如下结果:
+---+
|num|
+---+
| 6 |
注意:
如果没有只出现一次的数字,输出 null 。
SELECT
MAX(num) AS num
FROM
(SELECT
num
FROM
my_numbers
GROUP BY num
HAVING COUNT(num) = 1) t1
620. 有趣的电影
难度简单86收藏分享切换为英文关注反馈
SQL架构
某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述。
作为该电影院的信息部主管,您需要编写一个 SQL查询,找出所有影片描述为非 boring
(不无聊) 的并且 id 为奇数 的影片,结果请按等级 rating
排列。
例如,下表 cinema
:
+---------+-----------+--------------+-----------+
| id | movie | description | rating |
+---------+-----------+--------------+-----------+
| 1 | War | great 3D | 8.9 |
| 2 | Science | fiction | 8.5 |
| 3 | irish | boring | 6.2 |
| 4 | Ice song | Fantacy | 8.6 |
| 5 | House card| Interesting| 9.1 |
+---------+-----------+--------------+-----------+
对于上面的例子,则正确的输出是为:
+---------+-----------+--------------+-----------+
| id | movie | description | rating |
+---------+-----------+--------------+-----------+
| 5 | House card| Interesting| 9.1 |
| 1 | War | great 3D | 8.9 |
+---------+-----------+--------------+-----------+
select id,movie,description,rating
from cinema
where id%2=1 and description !='boring'
order by rating desc,id,movie,description
626. 换座位
难度中等
SQL架构
小美是一所中学的信息科技老师,她有一张 seat
座位表,平时用来储存学生名字和与他们相对应的座位 id。
其中纵列的 id 是连续递增的
小美想改变相邻俩学生的座位。
你能不能帮她写一个 SQL query 来输出小美想要的结果呢?
示例:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+---------+---------+
假如数据输入的是上表,则输出结果如下:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+---------+---------+
注意:
如果学生人数是奇数,则不需要改变最后一个同学的座位。
开窗
select id,
(case when id%2=0 then f
when id%2=1 && b is not null then b
else student end) student
from(
select id,student,
lag(student,1,null) over(order by id) f,
lead(student,1,null) over(order by id) b
from seat
)t1
非嵌套
select
if(id%2=0,
id-1,
if(id=(select count(distinct id) from seat),
id,
id+1))
as id,student
from seat
order by id;
用异或
select b.id,a.student from
seat as a,seat as b,(select count(*) as cnt from seat) as c
where b.id=1^(a.id-1)+1
-- where a.id=1^(b.id-1)+1; 也可以这样写,更容易理解
|| (c.cnt%2 && b.id=c.cnt && a.id=c.cnt);
627. 交换工资
难度简单
SQL架构
给定一个 salary
表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。
注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。
例如:
id | name | sex | salary |
---|---|---|---|
1 | A | m | 2500 |
2 | B | f | 1500 |
3 | C | m | 5500 |
4 | D | f | 500 |
运行你所编写的更新语句之后,将会得到以下表:
id | name | sex | salary |
---|---|---|---|
1 | A | f | 2500 |
2 | B | m | 1500 |
3 | C | f | 5500 |
4 | D | m | 500 |
UPDATE salary
SET
sex = CASE sex
WHEN 'm' THEN 'f'
ELSE 'm'
END;
Update 和set的使用
1045. 买下所有产品的客户
难度中等
SQL架构
Customer
表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| customer_id | int |
| product_key | int |
+-------------+---------+
product_key 是 Customer 表的外键。
Product
表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_key | int |
+-------------+---------+
product_key 是这张表的主键。
写一条 SQL 查询语句,从 Customer
表中查询购买了 Product
表中所有产品的客户的 id。
示例:
Customer 表:
+-------------+-------------+
| customer_id | product_key |
+-------------+-------------+
| 1 | 5 |
| 2 | 6 |
| 3 | 5 |
| 3 | 6 |
| 1 | 6 |
+-------------+-------------+
Product 表:
+-------------+
| product_key |
+-------------+
| 5 |
| 6 |
+-------------+
Result 表:
+-------------+
| customer_id |
+-------------+
| 1 |
| 3 |
+-------------+
购买了所有产品(5 和 6)的客户的 id 是 1 和 3 。
select customer_id
from Customer
group by customer_id
having count(distinct product_key)=(
select count(*) cnt
from Product)
1050. 合作过至少三次的演员和导演
难度简单
SQL架构
ActorDirector
表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| actor_id | int |
| director_id | int |
| timestamp | int |
+-------------+---------+
timestamp 是这张表的主键.
写一条SQL查询语句获取合作过至少三次的演员和导演的 id 对 (actor_id, director_id)
示例:
ActorDirector 表:
+-------------+-------------+-------------+
| actor_id | director_id | timestamp |
+-------------+-------------+-------------+
| 1 | 1 | 0 |
| 1 | 1 | 1 |
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 1 | 2 | 4 |
| 2 | 1 | 5 |
| 2 | 1 | 6 |
+-------------+-------------+-------------+
Result 表:
+-------------+-------------+
| actor_id | director_id |
+-------------+-------------+
| 1 | 1 |
+-------------+-------------+
唯一的 id 对是 (1, 1),他们恰好合作了 3 次。
select actor_id,director_id
from ActorDirector
group by actor_id,director_id
having count(*)>=3
1068. 产品销售分析 I
难度简单
SQL架构
销售表 Sales
:
+-------------+-------+
| Column Name | Type |
+-------------+-------+
| sale_id | int |
| product_id | int |
| year | int |
| quantity | int |
| price | int |
+-------------+-------+
(sale_id, year) 是销售表 Sales 的主键.
product_id 是产品表 Product 的外键.
注意: price 表示每单位价格
产品表 Product
:
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
+--------------+---------+
product_id 是表的主键.
写一条SQL 查询语句获取产品表 Product
中所有的 产品名称 product name 以及 该产品在 Sales
表中相对应的 上市年份 year 和 价格 price。
示例:
Sales 表:
+---------+------------+------+----------+-------+
| sale_id | product_id | year | quantity | price |
+---------+------------+------+----------+-------+
| 1 | 100 | 2008 | 10 | 5000 |
| 2 | 100 | 2009 | 12 | 5000 |
| 7 | 200 | 2011 | 15 | 9000 |
+---------+------------+------+----------+-------+
Product 表:
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 100 | Nokia |
| 200 | Apple |
| 300 | Samsung |
+------------+--------------+
Result 表:
+--------------+-------+-------+
| product_name | year | price |
+--------------+-------+-------+
| Nokia | 2008 | 5000 |
| Nokia | 2009 | 5000 |
| Apple | 2011 | 9000 |
+--------------+-------+-------+
select product_name,year,price
from Sales s left join Product p
on s.product_id = p.product_id