【问题标题】:Leetcode MySQL Hard Question - My Query is not passing second testcaseLeetcode MySQL 难题 - 我的查询没有通过第二个测试用例
【发布时间】:2022-01-16 12:54:52
【问题描述】:

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

问题链接: 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

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

编写一个 SQL 查询,查找“2013-10-01”和“2013-10-03”之间每天未禁止用户(客户端和驱动程序均不得禁止)的请求的取消率。取消率四舍五入到小数点后两位。

以任意顺序返回结果表。

查询结果格式如下例。

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", "completed", "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", "No", "client"], ["2 ", "Yes", "client"], ["3", "No", "client"], ["4", "No", "client"], ["10", "No", "driver "], ["11", "No", "driver"], ["12", "No", "driver"], ["13", "No", "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", "No", "client"], ["10", "No", "driver"]]}}

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

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

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

【问题讨论】:

  • 我有一个解决方案,并添加了关于您的代码为何未能通过测试用例的解释。你几乎步入正轨。在您的代码中,您应该为每次行程验证司机和客户均未禁止。相反,您的代码会检查未禁止客户的游乐设施(即使司机可能被禁止),并添加到未禁止司机的游乐设施(即使可能禁止客户)。
  • 感谢@zedfoxus 在下面的详细解释!欣赏它!为你干杯!
  • 绝对!你是如此接近。把写得好的问题和你的代码一起归功于自己。干得好。

标签: mysql sql common-table-expression


【解决方案1】:

啊,我明白你在做什么。使用相同的思路,但改用 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”、“否”、“驱动程序”]]]

此测试失败,因为您的代码在 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”、“否”、“驱动程序”]]]

此案例接下来将失败,因为您的 Requests_Total 使用未禁止的客户端的行程(忽略该行程中的驱动程序可能被禁止的事实)并且 UNIONs 使用未禁止的驱动程序(忽略该客户端上的事实旅行可能会被禁止。你不应该联合他们。

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

解决方法是确保每次旅行都检查司机和客户是否被禁止。这就是我在代码中所做的。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2020-01-12
    • 2020-08-29
    相关资源
    最近更新 更多