Leetcode MySQL 难题 - 我的查询没有通过第二个测试用例

Leetcode MySQL Hard Question - My Query is not passing second testcase

我正在解决以下 Hard Leetcode SQL 问题。

Link 问题: https://leetcode.com/problems/trips-and-users/

问题:

+-------------+----------+
| Column Name | Type     |
+-------------+----------+
| id          | int      |
| client_id   | int      |
| driver_id   | int      |
| city_id     | int      |
| status      | enum     |
| request_at  | date     |     
+-------------+----------+
id is the primary key for this table.
The table holds all taxi trips. Each trip has a unique id, while client_id and driver_id are foreign keys to the users_id at the Users table.
Status is an ENUM type of ('completed', 'cancelled_by_driver', 'cancelled_by_client').

Picture 1

+-------------+----------+
| Column Name | Type     |
+-------------+----------+
| users_id    | int      |
| banned      | enum     |
| role        | enum     |
+-------------+----------+
users_id is the primary key for this table.
The table holds all users. Each user has a unique users_id, and role is an ENUM type of ('client', 'driver', 'partner').
banned is an ENUM type of ('Yes', 'No').

Picture 2

取消率的计算方法是用当天取消的(由客户或 driver)未禁止用户的请求数除以未禁止用户的请求总数。

写一个SQL查询来查找在“2013-10-01”和“2013”​​之间每天有未被禁止的用户(客户端和driver都不能被禁止)的请求取消率-10-03”。取消率四舍五入到小数点后两位。

Return 结果 table 任意顺序。

查询结果格式如下例

Trips table:
+----+-----------+-----------+---------+---------------------+------------+
| id | client_id | driver_id | city_id | status              | request_at |
+----+-----------+-----------+---------+---------------------+------------+
| 1  | 1         | 10        | 1       | completed           | 2013-10-01 |
| 2  | 2         | 11        | 1       | cancelled_by_driver | 2013-10-01 |
| 3  | 3         | 12        | 6       | completed           | 2013-10-01 |
| 4  | 4         | 13        | 6       | cancelled_by_client | 2013-10-01 |
| 5  | 1         | 10        | 1       | completed           | 2013-10-02 |
| 6  | 2         | 11        | 6       | completed           | 2013-10-02 |
| 7  | 3         | 12        | 6       | completed           | 2013-10-02 |
| 8  | 2         | 12        | 12      | completed           | 2013-10-03 |
| 9  | 3         | 10        | 12      | completed           | 2013-10-03 |
| 10 | 4         | 13        | 12      | cancelled_by_driver | 2013-10-03 |
+----+-----------+-----------+---------+---------------------+------------+

Picture 3

Users table:
+----------+--------+--------+
| users_id | banned | role   |
+----------+--------+--------+
| 1        | No     | client |
| 2        | Yes    | client |
| 3        | No     | client |
| 4        | No     | client |
| 10       | No     | driver |
| 11       | No     | driver |
| 12       | No     | driver |
| 13       | No     | driver |
+----------+--------+--------+

Picture 4

Output: 
+------------+-------------------+
| Day        | Cancellation Rate |
+------------+-------------------+
| 2013-10-01 | 0.33              |
| 2013-10-02 | 0.00              |
| 2013-10-03 | 0.50              |
+------------+-------------------+

Picture 5

这是我的代码:

WITH Requests_Cancelled AS (
    SELECT Trips.client_id as ID, Trips.request_at as Day, COUNT(*) as cancelled_count
    FROM Trips
    INNER JOIN Users ON
    Trips.client_id = Users.users_id
    WHERE Users.banned = "No" AND Users.role = "client" AND Trips.status = "cancelled_by_client"
    GROUP BY Trips.request_at
    UNION
    SELECT Trips.driver_id as ID, Trips.request_at as Day, COUNT(*) as cancelled_count
    FROM Trips
    INNER JOIN Users ON
    Trips.driver_id = Users.users_id
    WHERE Users.banned = "No" AND Users.role = "driver" AND Trips.status = "cancelled_by_driver"
    GROUP BY Trips.request_at
),

Requests_Total AS (
    SELECT Trips.client_id as ID, Trips.request_at as Day, COUNT(*) as total_count
    FROM Trips
    INNER JOIN Users ON
    Trips.client_id = Users.users_id
    WHERE Users.banned = "No" AND Users.role = "client"
    GROUP BY Trips.request_at
    UNION
    SELECT Trips.driver_id as ID, Trips.request_at as Day, COUNT(*) as total_count
    FROM Trips
    INNER JOIN Users ON
    Trips.driver_Id = Users.users_id
    WHERE Users.banned = "No" AND Users.role = "driver"
    GROUP BY Trips.request_at
)

SELECT Requests_Total.Day, IFNULL(MAX(ROUND(Requests_Cancelled.cancelled_count/Requests_Total.total_count, 2)), 0) as 'Cancellation Rate' 
FROM Requests_Cancelled
RIGHT JOIN Requests_Total ON
Requests_Cancelled.Day = Requests_Total.Day
GROUP BY Requests_Total.Day
ORDER BY Requests_Total.Day ASC;

代码通过了下面的第一个测试用例:

输入: {"headers": {"Trips": ["id", "client_id", "driver_id", "city_id", "status", "request_at"], "Users": ["users_id", "banned", "role"]}, "rows": {"Trips" : [["1", "1", "10", "1", "完成", "2013-10-01"], ["2", "2", "11", "1", " cancelled_by_driver", "2013-10-01"], ["3", "3", "12", "6", "完成", "2013-10-01"], ["4" , "4", "13", "6", "cancelled_by_client", "2013-10-01"], ["5", "1", "10", "1", "完成" , "2013-10-02"], ["6", "2", "11", "6", "完成", "2013-10-02"], ["7", "3", " 12", "6", "完成", "2013-10-02"], ["8", "2", "12", "12", "完成", "2013-10-03"], ["9", "3", "10", "12", "完成", "2013-10-03"], ["10", "4", "13", "12", "cancelled_by_driver", "2013-10-03"]], "用户": [["1", "否", "客户端"], ["2", "是", "客户端"], [" 3", "否", "客户端"], ["4", "否", "客户端"], ["10", "否", "driver"], ["11", "否", "driver"], ["12", "否", "driver"], ["13", "否", "driver"]]}}

输出: {"headers": ["Day", "Cancellation Rate"], "values": [["2013-10-01", 0.33], ["2013-10-02", 0.00], ["2013-10-03", 0.50]]}

预期: {"headers": ["Day", "Cancellation Rate"], "values": [["2013-10-01", 0.33], ["2013-10-02", 0.00], ["2013-10-03", 0.50]]}

但是没有通过第二个测试用例:

输入: {"headers": {"Trips": ["id", "client_id", "driver_id", "city_id", "status", "request_at"], "Users": ["users_id", "banned", "role"]}, "rows": {"Trips" :[[“1”,“1”,“10”,“1”,“cancelled_by_client”,“2013-10-04”]],“用户”:[[“1”,“否” , "客户端"], ["10", "否", "driver"]]}}

输出: {"headers": ["Day", "Cancellation Rate"], "values": [["2013-10-04", 1.00]] }

预期: {"headers":["Day","Cancellation Rate"],"values":[]}

我不明白为什么第二个测试用例中需要 NULL 值。

啊,我明白你在做什么了。使用相同的思路,但切换到使用 request_date 而不是客户端 ID。


取消订单

select request_at, count(*) as cancels, 0 as requests
from trips t
join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
where t.status in ('cancelled_by_driver', 'cancelled_by_client')
    and t.request_at between '2013-10-01' and '2013-10-03'
group by request_at

获取您的乘车请求

select request_at, 0 as cancels, count(*) as requests
from trips t
join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
where t.request_at between '2013-10-01' and '2013-10-03'
group by request_at

将它们合并在一起

select request_at, count(*) as cancels, 0 as requests
from trips t
join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
where t.status in ('cancelled_by_driver', 'cancelled_by_client')
    and t.request_at between '2013-10-01' and '2013-10-03'
group by request_at

union all

select request_at, 0 as cancels, count(*) as requests
from trips t
join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
where t.request_at between '2013-10-01' and '2013-10-03'
group by request_at

现在,对于每一天,您都有一行包含取消计数和零请求计数。对于每一天,您都有一行零取消计数和有效请求计数。


最终结果

select request_at as "Day",
   round(coalesce(sum(cancels), 0)/coalesce(sum(requests), 0)/1.0, 2) as "Cancellation Rate"
from
(
    select request_at, count(*) as cancels, 0 as requests
    from trips t
    join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
    join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
    where t.status in ('cancelled_by_driver', 'cancelled_by_client')
        and t.request_at between '2013-10-01' and '2013-10-03'
    group by request_at
    
    union all
    
    select request_at, 0 as cancels, count(*) as requests
    from trips t
    join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
    join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
    where t.request_at between '2013-10-01' and '2013-10-03'
    group by request_at
) main
group by request_at

这会给你想要的。

这可能会更快,因为您每天在一个查询中收到取消请求,而在另一个查询中收到请求。对于您的最终结果,您不必再进行任何联接。

例子

https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=2b5dc7262d5c7839ddb39ab02e365821


基于此的精简版

select request_at as "Day", 
  round(
    coalesce(count( if(t.status != 'completed', 1.0, null) ), 0.0)
    /
    coalesce(count(*), 0.0)
  , 2) as "Cancellation Rate"
from trips t
join users uc on t.client_id = uc.users_id and 'No' = uc.banned and 'client' = uc.role
join users ud on t.driver_id = ud.users_id and 'No' = ud.banned and 'driver' = ud.role
where t.request_at between '2013-10-01' and '2013-10-03'
group by request_at

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8a223073878fab69b3859f7853609844


为什么你的代码没有通过测试?

  • “行程”:[[“1”、“1”、“10”、“1”、“cancelled_by_client”、“2013-10-04”]]
  • “用户”:[[“1”、“否”、“客户端”]、[“10”、“否”、“driver”]]

此测试失败,因为您的代码在 where 子句中没有 and request_at between '2013-10-01' and '2013-10-03'。您可以查看以下示例:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=58f638d2fccd9a2c4429c345c9dc43cb


即使对您的代码进行了上述更正,另一个案例也会失败。为什么?

  • {"行程": [["1111", "1", "10", "1", "完成", "2013-10-01"]],
  • “用户”:[[“1”,“是”,“客户”],[“10”,“否”,“driver”]]

接下来这个案例将失败,因为您的 Requests_Total 从未被禁止的客户那里进行旅行(忽略该旅行中的 driver 可能被禁止的事实)并且 UNION 将其与未被禁止的客户联系起来driver(忽略了那个旅行中的客户可能被禁止的事实。你不应该联合他们。

SELECT trips.request_at as Day, COUNT(*) as total_count
FROM trips
INNER JOIN users ON
trips.client_id = users.users_id
WHERE users.banned = "No" AND users.role = "client"
and request_at between '2013-10-01' and '2013-10-03'
GROUP BY trips.request_at
UNION
SELECT trips.request_at as Day, COUNT(*) as total_count
FROM trips
INNER JOIN users ON
trips.driver_Id = users.users_id
WHERE users.banned = "No" AND users.role = "driver"
and request_at between '2013-10-01' and '2013-10-03'
GROUP BY trips.request_at

修复是为了确保您在每次旅行中都检查 driver 和客户是否被禁止。这就是我在代码中所做的。

这是您的代码的结果,您可以在闲暇时对其进行调整。 https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=57e6d83db05a5cb4f99e715ccb133032