排版好有颜色的文章在公众号“八哥的成长心路札记”上有,微信号是bager1912。
以下题目均来自力扣(LeetCode)官网和其他网站,仅用作数据库爱好者学习交流,严禁进行商业及任何非法用途。
603. 连续空余座位
几个朋友来到电影院的售票处,准备预约连续空余座位。
你能利用表 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 distinct a.seat_id
from cinema a,cinema b
where (a.seat_id-1=b.seat_id or a.seat_id+1=b.seat_id) and (a.free=1 and b.free=1)
order by a.seat_id;
607. 销售员
描述
给定 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 o join company c
on o.com_id=c.com_id
where c.name='RED');
608. 树节点
给定一个表 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,'Root' Type
from tree
where p_id is null
union
select id,'Inner' Type
from tree
where id in (select distinct p_id
from tree
where p_id is not null) and p_id is not null
union
select id,'Leaf' Type
from tree
where id not in (select distinct p_id
from tree
where p_id is not null) and p_id is not null
order by id;
610. 判断三角形
一个小学生 Tim 的作业是判断三条线段是否能形成一个三角形。
然而,这个作业非常繁重,因为有几百组线段需要判断。
假设表 table
保存了所有三条线段的三元组 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 triangle.*,(case when x+y>z and x+z>y and y+z>x then 'Yes' else 'No' end) "triangle"
from triangle;
这个LeetCode让我有点郁闷,把表名字命名为table,也是无语了,看了评论说是表名为triangle。
612. 平面上的最近距离
表 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(power((p1.x-p2.x),2)+power((p1.y-p2.y),2))),2) "shortest"
from point_2d p1 join point_2d p2
on p1.x!=p2.x or p1.y!=p2.y;
613. 直线上的最近距离
表 point
保存了一些点在 x 轴上的坐标,这些坐标都是整数。
写一个查询语句,找到这些点中最近两个点之间的距离。
| x | |-----| | -1 | | 0 | | 2 |
最近距离显然是 '1' ,是点 '-1' 和 '0' 之间的距离。所以输出应该如下:
| shortest| |---------| | 1 |
注意:每个点都与其他点坐标不同,表 table
不会有重复坐标出现。
进阶:如果这些点在 x 轴上从左到右都有一个编号,输出结果时需要输出最近点对的编号呢?
select min(abs(p1.x-p2.x)) "shortest"
from point p1,point p2
where p1.x!=p2.x;
614. 二级关注者
在 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 distinct f2.follower,f1.num
from (select followee,nvl(count(distinct cn),0) num
from
(select followee,concat(followee,follower) cn
from follow)
group by followee) f1 join follow f2
on f1.followee=f2.follower
order by f2.follower;
这道题怎么改提交都不通过,很奇怪,不知道哪个地方有问题,而相似的mysql版本的却能通过,知道的朋友麻烦告诉我下,谢谢?
SELECT DISTINCT f2.follower,f1.num
FROM (SELECT followee, IFNULL(COUNT(DISTINCT followee,follower),0) AS num
FROM follow
GROUP BY followee) f1
INNER JOIN follow f2
ON f1.followee = f2.follower
ORDER BY f2.follower
;
615. 平均工资:部门与公司比较
给如下两个表,写一个查询语句,求出在每一个工资发放日,每个部门的平均工资与公司的平均工资的比较结果 (高 / 低 / 相同)。
表: 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 dt "pay_month",department_id "department_id",case when bv>av then 'higher'
when bv=av then 'same'
else 'lower' end "comparison"
from (select dt,department_id,av,avg(amount) bv
from (select to_char(pay_date,'YYYY-MM') dt,avg(amount) av
from salary
group by to_char(pay_date,'YYYY-MM')) s,salary s1,employee e
where s1.employee_id=e.employee_id and s.dt=to_char(s1.pay_date,'YYYY-MM')
group by dt,department_id,av)
order by department_id,dt;
这个地方注意下分组,group by to_char(pay_date,'YYYY-MM'),而不能是group by pay_date。
618. 学生地理信息报告
一所美国大学有来自亚洲、欧洲和美洲的学生,他们的地理信息存放在如下 student
表中。
| name | continent | |--------|-----------| | Jack | America | | Pascal | Europe | | Xi | Asia | | Jane | America |
写一个查询语句实现对大洲(continent)列的 透视表 操作,使得每个学生按照姓名的字母顺序依次排列在对应的大洲下面。输出的标题应依次为美洲(America)、亚洲(Asia)和欧洲(Europe)。数据保证来自美洲的学生不少于来自亚洲或者欧洲的学生。
对于样例输入,它的对应输出是:
| America | Asia | Europe | |---------|------|--------| | Jack | Xi | Pascal | | Jane | | |
进阶:如果不能确定哪个大洲的学生数最多,你可以写出一个查询去生成上述学生报告吗?
select a "America",b "Asia",c "Europe"
from (select rn,min(case continent when 'America' then name else '' end) a ,
min(case continent when 'Asia' then name else '' end) b ,
min(case continent when 'Europe' then name else '' end) c
from (select student.*,row_number() over(partition by continent order by name) rn
from student)
group by rn)
order by a,b,c;
想了蛮久,竟然被我想出来了,不容易。这个min好像换成max也可以的。因为排序函数已经按字母顺序排好序了。但是最外面一层还需要加个order by,因为对于continent内部是排好序了,但是外面对于同一层,比如都是2,都是3的那一层并没有排序。
既然做到了行列互换,那就再记录下今天做到的另一题,算是用sql进行多行多列相互转换,以此记录:
导进plsql developer里如图所示:
经过一番折腾,终于变换成功:
八哥觉得看着不爽,一定要按照既定要求显示,于是改改代码:
现在是对了,让我们来显示中文看看:
这么看着很完美,八哥略有点点成就感,如果需要源代码的朋友欢迎点赞,转发,或留言(#^.^#)没有的话,八哥就私藏了哈
619. 只出现一次的最大数字
表 my_numbers
的 num 字段包含很多数字,其中包括很多重复的数字。
你能写一个 SQL 查询语句,找到只出现过一次的数字中,最大的一个数字吗?
+---+ |num| +---+ | 8 | | 8 | | 3 | | 3 | | 1 | | 4 | | 5 | | 6 |
对于上面给出的样例数据,你的查询语句应该返回如下结果:
+---+ |num| +---+ | 6 |
注意:
如果没有只出现一次的数字,输出 null 。
select max(num) "num"
from my_numbers
where num in (select num
from my_numbers
group by num
having count(*)=1);
620. 有趣的电影
某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 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 *
from cinema
where id%2=1 and description!='boring'
order by rating desc;
626. 换座位
小美是一所中学的信息科技老师,她有一张 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 (CASE
WHEN MOD(id,2) = 1 AND id = (SELECT COUNT(*) FROM seat) THEN id
WHEN MOD(id,2) = 1 THEN id+1
ElSE id-1
END) AS id, student
FROM seat
ORDER BY id;
摘自blacksheep,这个思路太好了。
627. 交换工资
给定一个 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;
感觉这道题应该叫交换性别,有木有。。。
1045. Customers Who Bought All Products
Table: Customer
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| customer_id | int |
| product_key | int |
+-------------+---------+
product_key is a foreign key to Product
table.
Table: Product
+-------------+---------+ | Column Name | Type | +-------------+---------+ | product_key | int | +-------------+---------+ product_key is the primary key column for this table.
Write an SQL query for a report that provides the customer ids from the Customer
table that bought all the products in the Product
table.
For example:
Customer table: +-------------+-------------+ | customer_id | product_key | +-------------+-------------+ | 1 | 5 | | 2 | 6 | | 3 | 5 | | 3 | 6 | | 1 | 6 | +-------------+-------------+ Product table: +-------------+ | product_key | +-------------+ | 5 | | 6 | +-------------+ Result table: +-------------+ | customer_id | +-------------+ | 1 | | 3 | +-------------+ The customers who bought all the products (5 and 6) are customers with id 1 and 3.
select distinct customer_id
from customer
where product_key in (select product_key
from product)
group by customer_id
having count(*)=(select count(*)
from product);
这个做法在LeetCode里死活无法通过,试了好几种类似的写法,均提交失败,哪位大神更懂的给指指路,谢谢!
1050. Actors and Directors Who Cooperated At Least Three Times
able: ActorDirector
+-------------+---------+ | Column Name | Type | +-------------+---------+ | actor_id | int | | director_id | int | | timestamp | int | +-------------+---------+ timestamp is the primary key column for this table.
Write a SQL query for a report that provides the pairs (actor_id, director_id)
where the actor have cooperated with the director at least 3 times.
Example:
ActorDirector table: +-------------+-------------+-------------+ | 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 table: +-------------+-------------+ | actor_id | director_id | +-------------+-------------+ | 1 | 1 | +-------------+-------------+ The only pair is (1, 1) where they cooperated exactly 3 times.
select actor_id,director_id
from (select actor_id,director_id,count(*) cn
from actordirector
group by actor_id,director_id)
where cn>=3;
至此,截止2019年05月28日,LeetCode数据库全部44题,已全部解析完毕,鉴于个人能力有限,难免会有些许差错,欢迎各位看官批评指正,提出新的想法或建议,八哥与你共同学习,一起成长!
本专题完结!