LeetCode-SQL(三)

leetcode 系列


262. 行程和用户

https://leetcode-cn.com/problems/trips-and-users/

在这里插入图片描述
在这里插入图片描述
写一段 SQL 语句查出 “2013-10-01” 至 “2013-10-03” 期间非禁止用户(乘客和司机都必须未被禁止)的取消率。非禁止用户即 Banned 为 No 的用户,禁止用户即 Banned 为 Yes 的用户。

取消率 的计算方式如下:(被司机或乘客取消的非禁止用户生成的订单数量) / (非禁止用户生成的订单总数)。

返回结果表中的数据可以按任意顺序组织。其中取消率 Cancellation Rate 需要四舍五入保留 两位小数 。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题:
1、限定日期
2、获取每个client和driver的状态
3、求每个行程的状态
4、根据日期group by聚合得到结果

SELECT A.Request_at as Day,
       CONVERT(format(sum(A.is_completed) / count(*), 2), decimal(10,2) ) "Cancellation Rate"
FROM (
         SELECT t.Request_at,
                t.status,
                case when  t.status <> "completed" then 1 else 0 end is_completed ,
                (SELECT banned FROM users WHERE users_id = t.client_id) client_status,
                (SELECT banned FROM users WHERE users_id = t.Driver_Id) driver_status
         FROM Trips t
         WHERE t.Request_at BETWEEN '2013-10-01' AND '2013-10-03'
     ) A
WHERE A.client_status = "No"
  AND A.driver_status = "No"
GROUP BY A.Request_at;

579. 查询员工的累计薪水🔒

https://leetcode-cn.com/problems/find-cumulative-salary-of-an-employee/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法一:先求最近 2 个月薪资
想法
分两步解决这个问题。第一步是求得一个员工最近 3 个月的累积薪资,然后把最近一个月薪资从包含它的数据中去除。

如果你觉得求一个员工 3 个月的累积薪资有难度,可以从 2 个月的累积薪资开始考虑。通过把 Employee 表与它自己做一个连接,你可以得到每个员工 2 个月的薪资表。

SELECT *
FROM
    Employee E1
        LEFT JOIN
    Employee E2 ON (E2.id = E1.id
        AND E2.month = E1.month - 1)
ORDER BY E1.id ASC , E1. month DESC
Id	Month	Salary	Id	Month	Salary

在这里插入图片描述

SELECT
    E1.id,
    E1.month,
    (IFNULL(E1.salary, 0) + IFNULL(E2.salary, 0)) AS Salary
FROM
    Employee E1
        LEFT JOIN
    Employee E2 ON (E2.id = E1.id
        AND E2.month = E1.month - 1)
ORDER BY E1.id ASC , E1.month DESC;
idmonthSalary
14100
1370
1250
1120
2250
2120
34130
33100
3240

类似的,你可以将此表再次连接来求得 3 个月的累计薪资。

SELECT
    E1.id,
    E1.month,
    (IFNULL(E1.salary, 0) + IFNULL(E2.salary, 0) + IFNULL(E3.salary, 0)) AS Salary
FROM
    Employee E1
        LEFT JOIN
    Employee E2 ON (E2.id = E1.id
        AND E2.month = E1.month - 1)
        LEFT JOIN
    Employee E3 ON (E3.id = E1.id
        AND E3.month = E1.month - 2)
ORDER BY E1.id ASC , E1.month DESC;
idmonthSalary
14130
1390
1250
1120
2250
2120
34170
33100
3240

除此以外,我们还需要按要求去除最近一个月薪资的影响。如果我们有一个包含了每个 id 和该员工最近一个月是几月的临时表,我们就可以很轻易地把每个员工最近一个月的工资去除。

idmonth
14
22
34

下面是生成此表的代码。

SELECT
    id, MAX(month) AS month
FROM
    Employee
GROUP BY id
HAVING COUNT(*) > 1;

最后,我们把这两张表连接起来得到我们想要的连续 3 个月薪资但不包含最近一个月薪资的结果。

SELECT
    E1.id,
    E1.month,
    (IFNULL(E1.salary, 0) + IFNULL(E2.salary, 0) + IFNULL(E3.salary, 0)) AS Salary
FROM
    (SELECT
        id, MAX(month) AS month
    FROM
        Employee
    GROUP BY id
    HAVING COUNT(*) > 1) AS maxmonth
        LEFT JOIN
    Employee E1 ON (maxmonth.id = E1.id
        AND maxmonth.month > E1.month)
        LEFT JOIN
    Employee E2 ON (E2.id = E1.id
        AND E2.month = E1.month - 1)
        LEFT JOIN
    Employee E3 ON (E3.id = E1.id
        AND E3.month = E1.month - 2)
ORDER BY id ASC , month DESC;

方法二:直接计算所有需要累计的月份
想法

我们可以先用一个查询求得对于每个员工来说需要累计的月份,然后将这些月份对应的前两月的工资相加。

每个员工需要进行累计的月份是除他的最大月份外的所有月份,按员工分组并用 max 聚合函数可以求得每个员工的最大月份。求得最大月份后,再查询对于每个员工来说所有不等于最大月份的月份。这些月份即为需要累计的月份。

select Employee.Id as Id, Employee.Month as Month
from Employee, (select Id, max(Month) as Month
    from Employee
    group by Id) as LastMonth
    where Employee.Id = LastMonth.Id and Employee.Month != LastMonth.Month

然后对于每个需要累计的月份,记录它的前两个月份,将对应关系记录到一个表中,这样的查询可以通过 join 语句实现。

select a.Id as Id, a.Month as AccMonth, b.Month as Month, b.Salary as Salary
from 
(
    select Employee.Id as Id, Employee.Month as Month
    from Employee, (select Id, max(Month) as Month
        from Employee
        group by Id) as LastMonth
        where Employee.Id = LastMonth.Id and Employee.Month != LastMonth.Month) as a 
join Employee as b
on a.Id = b.Id and a.Month - b.Month <= 2 and a.Month - b.Month >= 0

进行上述查询后,对于题目的输入,可以得到这样一张表(为了方便理解,这里对表进行了排序):

IdAccMonthMonthSalary
11120
12120
12230
13120
13230
13340
21120
32240
33240
33360

可以看到,AccMonth 对应每个需要输出的累计月份,而 AccMonth 对应的 Month 其前三个月份。所以此时只要按照员工 Id 与需要累计的月份 AccMonth 分组,并用 sum 聚合函数计算累计工资即可。

select Id, AccMonth as Month, sum(Salary) as Salary
from
(
    select a.Id as Id, a.Month as AccMonth, b.Month as Month, b.Salary as Salary
    from 
    (
        select Employee.Id as Id, Employee.Month as Month
        from Employee, (select Id, max(Month) as Month
            from Employee
            group by Id) as LastMonth
            where Employee.Id = LastMonth.Id and Employee.Month != LastMonth.Month) as a 
    join Employee as b
    on a.Id = b.Id and a.Month - b.Month <= 2 and a.Month - b.Month >= 0
) as acc
group by Id, AccMonth
order by Id, Month desc;

603. 连续空余座位🔒

https://leetcode-cn.com/problems/consecutive-available-seats/
在这里插入图片描述
方法:使用自连接 join 和 abs() [Accepted]
想法

这个问题中只有一张表,所以我们需要使用自连接 self join 来解决这个相对复杂的问题。

算法

首先,我们看看将这个表自连接后得到什么结果。

注意:将两个表连接的结果是这两个表的 笛卡尔乘积 。

select a.seat_id, a.free, b.seat_id, b.free
from cinema a join cinema b;

为了找到连续空座位,a.seat_id 里面的值应该大于 b.seat_id 且两者都应该为空。

select a.seat_id, a.free, b.seat_id, b.free
from cinema a join cinema b
  on abs(a.seat_id - b.seat_id) = 1
  and a.free = true and b.free = true;

最后,选择上表中的字段 seat_id ,并排序后返回。

注意:你可能发现 seat_id 4 在表中出现了两次。这是因为座位 4 与 3 和 5 都相邻。所以我们需要使用 distinct 将重复记录筛除。

sql

select distinct a.seat_id
from cinema a join cinema b
  on abs(a.seat_id - b.seat_id) = 1
  and a.free = true and b.free = true
order by a.seat_id;

620. 有趣的电影

https://leetcode-cn.com/problems/not-boring-movies/
在这里插入图片描述

题解:使用 MOD() 函数
我们可以使用 mod(id,2)=1 来确定奇数 id,然后添加 description != ‘boring’ 来解决问题。

select *
from cinema
where mod(id, 2) = 1 and description != 'boring'
order by rating DESC;

1407. 排名靠前的旅行者🔒

https://leetcode-cn.com/problems/top-travellers/
在这里插入图片描述
写一段 SQL , 报告每个用户的旅行距离。

返回的结果表单,以 travelled_distance 降序排列 ,如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列 。

查询结果格式如下例所示。
在这里插入图片描述
在这里插入图片描述
题解:
从测试用例中可以看出,有用户的出行量是0.这里的问题在于,这样的用户在rides中没有出现,所以我们在使用users作为左边的表来join右边的rides的时候,使用left join,这样所有的用户就能够显示出来了。
光做到上面的还不够,因为得到的是null,而不是0,因此这里要使用coalesce这个函数对null进行处理。
就是这么简单!

select name, coalesce(sum(distance), 0) as travelled_distance
from users left join rides on users.id=rides.user_id
group by name
order by travelled_distance desc, name;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值