Table of contents
1173. Instant Food Delivery I
1174. Instant Food Delivery II
1193. Monthly Transactions I
1194. Championship Winner
1204. Last person to enter the elevator
1205. Monthly Transactions II
1211. Quality and proportion of query results
1212. Query Team points
1225. Consecutive dates for reporting system status
1241. Comments per post
1251. Average sale price
1264. Page recommendations
1270. All people reporting to the CEO of the company
1280. Number of tests students took in each subject
1285. Find the starting and ending numbers of a continuous interval
1173. Instant food delivery I
- source code:
select round(sum(case when order_date = customer_pref_delivery_date then 1 else 0 end) / count(delivery_id) * 100, 2) as immediate_percentage from delivery
- Idea:
sum() + case when
Using this method simplifies this question a lot. This is also an experience.
1174. Instant Food Delivery II
- source code:
with first_order as ( select delivery_id from delivery where (customer_id, order_date) in ( select customer_id, min(order_date) from delivery group by customer_id ) ) select round( sum(case when order_date=customer_pref_delivery_date and delivery_id in (select * from first_order) then 1 else 0 end) / (select count(*) from first_order) * 100 , 2) as immediate_percentage from delivery
- Idea: It is important to understand the demand. This question is to ask for the proportion of immediate orders among first-time orders. Therefore, we can first find out which first-time orders there are, and then use subqueries to determine the number of orders that are both immediate orders and first-time orders.
1193. Monthly Transactions I
- source code:
select left(trans_date, 7) as month, country, count(id) as trans_count, count(case when state = 'approved' then 1 else null end) as approved_count, sum(amount) as trans_total_amount, sum(case when state = 'approved' then amount else 0 end) as approved_total_amount from transactions group by left(trans_date, 7), country
- Idea: First we need to know how to get the date in front of the string. There are two ways
substr() / left()
; then figure out the grouping field and then perform aggregation.
1194. Tournament Winner
- source code:
select group_id, id player_id from ( select group_id, id, row_number() over(partition by group_id order by total_score desc, id) rk from ( select id, sum(score) total_score from ( select match_id, first_player id, first_score score from matches union all select match_id, second_player id, second_score score from matches ) t group by id ) t join players on t.id = players.player_id ) t where rk = 1
- Idea: According to the need to accumulate the scores of the players as mentioned in the question, that is, whether they are the first player or the second player, they need to be accumulated, so we can split one table into two tables
sum
. In this way, we can find the cumulative score of each player, and then find the player with the highest score in the group.
1204. The last person to enter the elevator
- source code:
select person_name from ( select person_name, sum(weight) over(order by turn) sum_weight from queue ) t where sum_weight <= 1000 order by sum_weight desc limit 1;
- Idea: By
sum
opening the window on the function, you can get the cumulative weight sum. As long as you take out the person who is less than or equal to 1000 and the largest, he will be the last person who has the right weight and enters the elevator.
1205. Monthly Transactions II **
- source code:
with base as ( select 'approved' tag, country, substr(trans_date, 1, 7) month, amount from Transactions where state = 'approved' union all select 'chargeback' tag, t.country, substr(cb.trans_date, 1, 7) month, t.amount from Chargebacks cb join Transactions t on cb.trans_id = t.id ) select month, country, sum(if(tag = 'approved', 1, 0)) approved_count, sum(if(tag = 'approved', amount, 0)) approved_amount, sum(if(tag = 'chargeback', 1, 0)) chargeback_count, sum(if(tag = 'chargeback', amount, 0)) chargeback_amount from base group by month, country;
- Idea: First label the data, and then
union all
perform grouping and aggregation; - Focus on learning the idea of this question. I remember asking for the maximum number of continuous online people in the live broadcast room. This is also the idea.
1211. Quality and proportion of query results
- source code:
select query_name, round(avg(rating / position), 2) quality, round(sum(case when rating < 3 then 1 else 0 end) / count(*) * 100, 2) poor_query_percentage from queries group by query_name
- Idea: The requirements are relatively simple, and there is no logic that is particularly difficult to understand.
1212. Query team points
- source code:
select team_id, team_name, ifnull(score, 0) as num_points from teams left join ( select id, sum(score) score from ( -- 作为主场 select host_team id, sum(case when host_goals > guest_goals then 3 when host_goals = guest_goals then 1 else 0 end) score from matches group by id union all -- 作为客场 select guest_team id, sum(case when host_goals < guest_goals then 3 when host_goals = guest_goals then 1 else 0 end) score from matches group by id ) t group by id ) t on teams.team_id = t.id order by num_points desc, team_id;
- Idea: The core logic is
left join
the logic on the right. We first calculate the home score, then calculate the away score, and finally add these two parts together.
1225. Report system status on consecutive dates **
- source code:
select type period_state , min(dt) start_date, max(dt) end_date from ( select type, dt, subdate(dt, row_number() over(partition by type order by dt)) diff from ( select 'succeeded' type, success_date dt from succeeded where success_date between '2019-01-01' and '2019-12-31' union select 'failed' type, fail_date dt from failed where fail_date between '2019-01-01' and '2019-12-31' ) t ) t group by type, diff order by start_date;
- Idea:
类似于求最大连续登陆天数问题
, the difference is that this question asks for the start and end time of continuous login! This question requires connecting two tables, and then you need to create a field yourself (a very good idea ), and then apply the maximum continuous login problem routinedate_sub + row_number
to solve it.
1241. Number of comments per post
- source code:
select sub_id post_id, ifnull(number_of_comments, 0) number_of_comments from ( select distinct sub_id from submissions where parent_id is null ) t1 left join ( select parent_id, count(distinct sub_id) number_of_comments from submissions where parent_id is not null group by parent_id ) t2 on t1.sub_id = t2.parent_id order by post_id;
- Idea: Just make it clear whether each piece of data is a post or a comment; then pay attention to removing duplicates!
1251. Average selling price
- source code:
select product_id, round(sum(price * units) / sum(units), 2) average_price from ( select p.product_id, price, units from prices p join unitssold u on p.product_id = u.product_id and purchase_date between start_date and end_date ) t group by product_id;
- Idea: relatively simple
1264. Page recommendation
- source code:
select distinct page_id as recommended_page from ( select page_id from likes where user_id in ( select case when user1_id = 1 then user2_id else user1_id end from friendship where user1_id = 1 or user2_id = 1 ) ) t where page_id not in ( select page_id from likes where user_id = 1 ) ;
- Idea: It’s relatively simple, you just need to pay attention to some of the details.
1270. Everyone who reports to the CEO of the company *
- source code:
select e3.employee_id from employees e1, employees e2, employees e3 where -- 根据题目说的要找出所有经理为1的员工id e1.manager_id = 1 and -- 根据上面一个条件找出直接经理为1的员工id,然后让这些员工id作为第二张表的经理,来获取所有的员工id e2.manager_id = e1.employee_id and -- 根绝上面一个条件找出直接或者间接一次得到的所有员工id,然后让这些员工id作为第三张表的经理,来获取所有的员工id e3.manager_id = e2.employee_id and -- 排除自己的经理就是自己的员工id e3.employee_id != 1 ;
- Idea: It is easy to get the answer to this question without writing a program, but it is more difficult to implement it through a program. I have explained the
where
meaning of each sentence in the above source code.
1280. Number of tests students took in each subject
- source code:
select t1.student_id, student_name, t1.subject_name, count(ex.student_id) attended_exams from ( select student_id, student_name, subject_name from students join subjects on 1 = 1 ) t1 left join examinations ex on t1.student_id = ex.student_id and t1.subject_name = ex.subject_name group by t1.student_id, t1.subject_name order by t1.student_id, t1.subject_name;
- Idea: It involves a Cartesian product connection , which can be used
cross join
1285. Find the starting and ending numbers of a continuous interval
- source code:
select min(log_id) start_id, max(log_id) end_id from ( select log_id, (log_id - row_number() over(order by log_id)) diff from logs ) t group by diff order by start_id
- Idea: Exactly the same as the above question, find the maximum and minimum time for continuous login