完结篇:LeetCode数据库最新44题190528Oracle版(3)

排版好有颜色的文章在公众号“八哥的成长心路札记”上有,微信号是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题,已全部解析完毕,鉴于个人能力有限,难免会有些许差错,欢迎各位看官批评指正,提出新的想法或建议,八哥与你共同学习,一起成长!

 

本专题完结!

你可能感兴趣的:(完结篇:LeetCode数据库最新44题190528Oracle版(3))