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
我正在解决以下 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