81. 获取最近第二次的活动
写一条SQL查询展示每一位用户 最近第二次 的活动,如果用户仅有一次活动,返回该活动。一个用户不能同时进行超过一项活动,以 任意 顺序返回结果。
展示效果:
+------------+--------------+-------------+-------------+| username | activity | startDate | endDate |+------------+--------------+-------------+-------------+| Alice | Dancing | 2020-02-21 | 2020-02-23 || Bob | Travel | 2020-02-11 | 2020-02-18 |+------------+--------------+-------------+-------------+
建表语句:
Create table If Not Exists 81_UserActivity (username varchar(30), activity varchar(30), startDate date, endDate date);Truncate table 81_UserActivity;insert into 81_UserActivity (username, activity, startDate, endDate) values ('Alice', 'Travel', '2020-02-12', '2020-02-20');insert into 81_UserActivity (username, activity, startDate, endDate) values ('Alice', 'Dancing', '2020-02-21', '2020-02-23');insert into 81_UserActivity (username, activity, startDate, endDate) values ('Alice', 'Travel', '2020-02-24', '2020-02-28');insert into 81_UserActivity (username, activity, startDate, endDate) values ('Bob', 'Travel', '2020-02-11', '2020-02-18');
最终SQL:
-- 方法一selectmax(u1.username) username,max(u1.activity) activity,max(u1.startdate) startdate,max(u1.enddate) enddatefrom81_useractivity u1join81_useractivity u2onu1.username = u2.usernamegroup byu1.username, u1.startdatehavingsum(if(u2.startdate > u1.startdate,1,0)) = 1orcount(1) = 1;-- 方法二select`username`,activity,startDate,endDatefrom(selectusername,activity,startDate,endDate ,rank() over(partition by username order by startDate desc) rk,lag(startDate ,1, null) over(partition by username order by startDate ) lgfrom 81_UserActivity) t1whererk=2 or (rk = 1 and lg is null)
82. 使用唯一标识码替换员工ID
写一段SQL查询来展示每位用户的 唯一标识码(unique ID );如果某位员工没有唯一标识码,使用 null 填充即可。你可以以 任意 顺序返回结果表。
展示效果:
+-----------+----------+| unique_id | name |+-----------+----------+| null | Alice || null | Bob || 2 | Meir || 3 | Winston || 1 | Jonathan |+-----------+----------+
建表语句:
Create table If Not Exists 82_Employees (id int, name varchar(20));Create table If Not Exists 82_EmployeeUNI (id int, unique_id int);Truncate table 82_Employees;insert into 82_Employees (id, name) values ('1', 'Alice');insert into 82_Employees (id, name) values ('7', 'Bob');insert into 82_Employees (id, name) values ('11', 'Meir');insert into 82_Employees (id, name) values ('90', 'Winston');insert into 82_Employees (id, name) values ('3', 'Jonathan');Truncate table 82_EmployeeUNI;insert into 82_EmployeeUNI (id, unique_id) values ('3', '1');insert into 82_EmployeeUNI (id, unique_id) values ('11', '2');insert into 82_EmployeeUNI (id, unique_id) values ('90', '3');
最终SQL:
selectif(unique_id is null, null, unique_id) as unique_id,e.namefrom82_Employees eleft join82_EmployeeUNI uone.id = u.id;
83. 按年度列出销售总额
编写一段SQL查询每个产品每年的总销售额,并包含 product_id, product_name 以及 report_year 等信息。销售年份的日期介于 2018 年到 2020 年之间。你返回的结果需要按 product_id 和 report_year 排序。
展示效果:
+------------+--------------+-------------+--------------+| product_id | product_name | report_year | total_amount |+------------+--------------+-------------+--------------+| 1 | LC Phone | 2019 | 3500 || 2 | LC T-Shirt | 2018 | 310 || 2 | LC T-Shirt | 2019 | 3650 || 2 | LC T-Shirt | 2020 | 10 || 3 | LC Keychain | 2019 | 31 || 3 | LC Keychain | 2020 | 31 |+------------+--------------+-------------+--------------+LC Phone 在 2019-01-25 至 2019-02-28 期间销售,该产品销售时间总计35天。销售总额 35*100 = 3500。LC T-shirt 在 2018-12-01 至 2020-01-01 期间销售,该产品在2018年、2019年、2020年的销售时间分别是31天、365天、1天,2018年、2019年、2020年的销售总额分别是31*10=310、365*10=3650、1*10=10。LC Keychain 在 2019-12-01 至 2020-01-31 期间销售,该产品在2019年、2020年的销售时间分别是:31天、31天,2019年、2020年的销售总额分别是31*1=31、31*1=31。
建表语句:
Create table If Not Exists 83_Product (product_id int, product_name varchar(30));Create table If Not Exists 83_Sales (product_id varchar(30), period_start date, period_end date, average_daily_sales int);Truncate table 83_Product;insert into 83_Product (product_id, product_name) values ('1', 'LC Phone ');insert into 83_Product (product_id, product_name) values ('2', 'LC T-Shirt');insert into 83_Product (product_id, product_name) values ('3', 'LC Keychain');Truncate table 83_Sales;insert into 83_Sales (product_id, period_start, period_end, average_daily_sales) values ('1', '2019-01-25', '2019-02-28', '100');insert into 83_Sales (product_id, period_start, period_end, average_daily_sales) values ('2', '2018-12-01', '2020-01-01', '10');insert into 83_Sales (product_id, period_start, period_end, average_daily_sales) values ('3', '2019-12-01', '2020-01-31', '1');
最终SQL:
(selects1.product_id,product_name,'2018' as 'report_year',if(period_start<'2019-01-01',(datediff(if(period_end<'2019-01-01', period_end, date('2018-12-31')),if(period_start>='2018-01-01', period_start, date('2018-01-01')))+1) * average_daily_sales, 0) as total_amountfrom83_Sales as s1join83_Product as p1ons1.product_id = p1.product_idhavingtotal_amount>0 )union(selects2.product_id,product_name,'2019' as 'report_year',if( period_start<'2020-01-01', (datediff(if(period_end<'2020-01-01', period_end, date('2019-12-31')), if(period_start>='2019-01-01', period_start, date('2019-01-01')))+1) * average_daily_sales , 0) as total_amountfrom83_Sales as s2join83_Product as p2ons2.product_id = p2.product_idhaving total_amount>0)union(selects3.product_id,product_name,'2020' as 'report_year',(datediff(if(period_end<'2021-01-01', period_end, date('2020-12-31')),if(period_start>='2020-01-01', period_start, date('2020-01-01')))+1) * average_daily_sales as total_amountfrom83_Sales as s3join83_Product as p3ons3.product_id = p3.product_idhaving total_amount>0 )order by product_id, report_year
84. 股票的资本损益
编写一个SQL查询来报告每支股票的资本损益。股票的资本损益是一次或多次买卖股票后的全部收益或损失。以任意顺序返回结果即可。
展示效果:
+---------------+-------------------+| stock_name | capital_gain_loss |+---------------+-------------------+| Corona Masks | 9500 || Leetcode | 8000 || Handbags | -23000 |+---------------+-------------------+Leetcode 股票在第一天以1000美元的价格买入,在第五天以9000美元的价格卖出。资本收益=9000-1000=8000美元。Handbags 股票在第17天以30000美元的价格买入,在第29天以7000美元的价格卖出。资本损失=7000-30000=-23000美元。Corona Masks 股票在第1天以10美元的价格买入,在第3天以1010美元的价格卖出。在第4天以1000美元的价格再次购买,在第5天以500美元的价格出售。最后,它在第6天以1000美元的价格被买走,在第10天以10000美元的价格被卖掉。资本损益是每次(’Buy'->'Sell')操作资本收益或损失的和=(1010-10)+(500-1000)+(10000-1000)=1000-500+9000=9500美元。
Create Table If Not Exists 84_Stocks(stock_name varchar(15),operation ENUM('Sell', 'Buy'),operation_day int, price int);Truncate table 84_Stocks;insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Leetcode', 'Buy', '1', '1000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Buy', '2', '10');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Leetcode', 'Sell', '5', '9000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Handbags', 'Buy', '17', '30000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Sell', '3', '1010');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Buy', '4', '1000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Sell', '5', '500');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Buy', '6', '1000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Handbags', 'Sell', '29', '7000');insert into 84_Stocks (stock_name, operation, operation_day, price) values ('Corona Masks', 'Sell', '10', '10000');
最终SQL:
-- 方法一selects2.stock_name,s2.sum_sell - s1.sum_buy as capital_gain_lossfrom(selectstock_name,sum(if(operation='Buy',price,0)) as sum_buy,sum(if(operation='Sell',price,0)) as sum_sellfrom84_stocksgroup bystock_name, operation) s1join(selectstock_name,sum(if(operation='Buy',price,0)) as sum_buy,sum(if(operation='Sell',price,0)) as sum_sellfrom84_stocksgroup bystock_name, operation) s2ons1.stock_name = s2.stock_namewheres1.sum_buy <> 0ands2.sum_buy = 0;-- 方法二selectstock_name,sell-buy capital_gain_lossfrom(selectstock_name,sum(if(operation='Buy', price,0))over(partition by stock_name ) buy,sum(if(operation='Sell',price,0))over(partition by stock_name) sellfrom84_Stocks s )t1group bystock_name,buy,sell;
85. 购买了产品A和B却没有购买产品C的顾客
请你设计 SQL 查询来报告购买了产品 A 和产品 B 却没有购买产品 C 的顾客的 ID 和姓名( customer_id 和 customer_name ),我们将基于此结果为他们推荐产品 C 。
您返回的查询结果需要按照 customer_id 排序。
展示效果:
+-------------+---------------+| customer_id | customer_name |+-------------+---------------+| 3 | Elizabeth |+-------------+---------------+
建表语句:
Create table If Not Exists 85_Customers (customer_id int, customer_name varchar(30));Create table If Not Exists 85_Orders (order_id int, customer_id int, product_name varchar(30));Truncate table 85_Customers;insert into 85_Customers (customer_id, customer_name) values ('1', 'Daniel');insert into 85_Customers (customer_id, customer_name) values ('2', 'Diana');insert into 85_Customers (customer_id, customer_name) values ('3', 'Elizabeth');insert into 85_Customers (customer_id, customer_name) values ('4', 'Jhon');Truncate table 85_Orders;insert into 85_Orders (order_id, customer_id, product_name) values ('10', '1', 'A');insert into 85_Orders (order_id, customer_id, product_name) values ('20', '1', 'B');insert into 85_Orders (order_id, customer_id, product_name) values ('30', '1', 'D');insert into 85_Orders (order_id, customer_id, product_name) values ('40', '1', 'C');insert into 85_Orders (order_id, customer_id, product_name) values ('50', '2', 'A');insert into 85_Orders (order_id, customer_id, product_name) values ('60', '3', 'A');insert into 85_Orders (order_id, customer_id, product_name) values ('70', '3', 'B');insert into 85_Orders (order_id, customer_id, product_name) values ('80', '3', 'D');insert into 85_Orders (order_id, customer_id, product_name) values ('90', '4', 'C');
最终SQL:
selecto.customer_id,customer_namefrom85_Orders oleft join85_Customers cono.customer_id=c.customer_idgroup bycustomer_idhavingsum(product_name ='A')>=1andsum(product_name='B')>=1andsum(product_name='C')=0;
86. 排名靠前的旅行者
写一段 SQL , 报告每个用户的旅行距离。返回的结果表单, 以 travelled_distance 降序排列, 如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列.
展示效果:
+----------+--------------------+| name | travelled_distance |+----------+--------------------+| Elvis | 450 || Lee | 450 || Bob | 317 || Jonathan | 312 || Alex | 222 || Alice | 120 || Donald | 0 |+----------+--------------------+Elvis 和 Lee 旅行了 450 英里, Elvis 是排名靠前的旅行者, 因为他的名字在字母表上的排序比 Lee 更小.Bob, Jonathan, Alex 和 Alice 只有一次行程, 我们只按此次行程的全部距离对他们排序.Donald 没有任何行程, 他的旅行距离为 0.
建表语句:
Create Table If Not Exists 86_Users (id int, name varchar(30));Create Table If Not Exists 86_Rides (id int, user_id int, distance int);Truncate table 86_Users;insert into 86_Users (id, name) values ('1', 'Alice');insert into 86_Users (id, name) values ('2', 'Bob');insert into 86_Users (id, name) values ('3', 'Alex');insert into 86_Users (id, name) values ('4', 'Donald');insert into 86_Users (id, name) values ('7', 'Lee');insert into 86_Users (id, name) values ('13', 'Jonathan');insert into 86_Users (id, name) values ('19', 'Elvis');Truncate table 86_Rides;insert into 86_Rides (id, user_id, distance) values ('1', '1', '120');insert into 86_Rides (id, user_id, distance) values ('2', '2', '317');insert into 86_Rides (id, user_id, distance) values ('3', '3', '222');insert into 86_Rides (id, user_id, distance) values ('4', '7', '100');insert into 86_Rides (id, user_id, distance) values ('5', '13', '312');insert into 86_Rides (id, user_id, distance) values ('6', '19', '50');insert into 86_Rides (id, user_id, distance) values ('7', '7', '120');insert into 86_Rides (id, user_id, distance) values ('8', '19', '400');insert into 86_Rides (id, user_id, distance) values ('9', '7', '230');
最终SQL:
selectname,sum(ifnull(distance,0)) travelled_distancefrom86_Users uleft join86_Rides ronu.id = r.user_idgroup bynameorder bytravelled_distance desc, name;
87. 查找成绩处于中游的学生
写一个 SQL 语句,找出在所有测验中都处于中游的学生 (student_id, student_name)。成绩处于中游的学生是指至少参加了一次测验, 且得分既不是最高分也不是最低分的学生。不要返回从来没有参加过测验的学生。返回结果表按照 student_id 排序。
展示效果:
+-------------+---------------+| student_id | student_name |+-------------+---------------+| 2 | Jade |+-------------+---------------+对于测验 1: 学生 1 和 3 分别获得了最低分和最高分。对于测验 2: 学生 1 既获得了最高分, 也获得了最低分。对于测验 3 和 4: 学生 1 和 4 分别获得了最低分和最高分。学生 2 和 5 没有在任一场测验中获得了最高分或者最低分。因为学生 5 从来没有参加过任何测验, 所以他被排除于结果表。由此, 我们仅仅返回学生 2 的信息。
建表语句:
Create table If Not Exists 87_Student (student_id int, student_name varchar(30));Create table If Not Exists 87_Exam (exam_id int, student_id int, score int);Truncate table 87_Student;insert into 87_Student (student_id, student_name) values ('1', 'Daniel');insert into 87_Student (student_id, student_name) values ('2', 'Jade');insert into 87_Student (student_id, student_name) values ('3', 'Stella');insert into 87_Student (student_id, student_name) values ('4', 'Jonathan');insert into 87_Student (student_id, student_name) values ('5', 'Will');Truncate table 87_Exam;insert into 87_Exam (exam_id, student_id, score) values ('10', '1', '70');insert into 87_Exam (exam_id, student_id, score) values ('10', '2', '80');insert into 87_Exam (exam_id, student_id, score) values ('10', '3', '90');insert into 87_Exam (exam_id, student_id, score) values ('20', '1', '80');insert into 87_Exam (exam_id, student_id, score) values ('30', '1', '70');insert into 87_Exam (exam_id, student_id, score) values ('30', '3', '80');insert into 87_Exam (exam_id, student_id, score) values ('30', '4', '90');insert into 87_Exam (exam_id, student_id, score) values ('40', '1', '60');insert into 87_Exam (exam_id, student_id, score) values ('40', '2', '70');insert into 87_Exam (exam_id, student_id, score) values ('40', '4', '80');
最终SQL:
selectstudent_id,student_namefrom87_studentwherestudent_id not in(selects1.student_idfrom87_student s1left join87_exam e1ons1.student_id = e1.student_idjoin(select max(score) max_score, min(score) min_score from 87_Exam) mone1.score = m.max_scoreore1.score = m.min_scoreore1.score is null);-- 方法二selecte.student_id,student_namefrom87_Exam eleft join87_Student sone.student_id=s.student_idwheree.student_id not in(selectstudent_idfrom(selectstudent_id,rank() over(partition by exam_id order by score desc) rkmax,rank() over(partition by exam_id order by score ) rkminfrom87_Exam )t1whererkmax = 1 or rkmin =1 )group bye.student_id,student_nameorder bye.student_id;
88. 净现值查询
写一个 SQL, 找到 Queries 表中每一次查询的净现值,结果表没有顺序要求.
展示效果:
+------+--------+--------+| id | year | npv |+------+--------+--------+| 1 | 2019 | 113 || 2 | 2008 | 121 || 3 | 2009 | 12 || 7 | 2018 | 0 || 7 | 2019 | 0 || 7 | 2020 | 30 || 13 | 2019 | 40 |+------+--------+--------+(7, 2018)的净现值不在 NPV 表中, 我们把它看作是 0.所有其它查询的净现值都能在 NPV 表中找到.
Create Table If Not Exists 88_NPV (id int, year int, npv int);Create Table If Not Exists 88_Queries (id int, year int);Truncate table 88_NPV;insert into 88_NPV (id, year, npv) values ('1', '2018', '100');insert into 88_NPV (id, year, npv) values ('7', '2020', '30');insert into 88_NPV (id, year, npv) values ('13', '2019', '40');insert into 88_NPV (id, year, npv) values ('1', '2019', '113');insert into 88_NPV (id, year, npv) values ('2', '2008', '121');insert into 88_NPV (id, year, npv) values ('3', '2009', '21');insert into 88_NPV (id, year, npv) values ('11', '2020', '99');insert into 88_NPV (id, year, npv) values ('7', '2019', '0');Truncate table 88_Queries;insert into 88_Queries (id, year) values ('1', '2019');insert into 88_Queries (id, year) values ('2', '2008');insert into 88_Queries (id, year) values ('3', '2009');insert into 88_Queries (id, year) values ('7', '2018');insert into 88_Queries (id, year) values ('7', '2019');insert into 88_Queries (id, year) values ('7', '2020');insert into 88_Queries (id, year) values ('13', '2019');
最终SQL:
selectq.id,q.year,ifnull(npv,0) npvfrom88_Queries qleft join88_NPV nonq.id = n.idandq.year = n.year;
89. 制作会话柱状图
你想知道用户在你的 app 上的访问时长情况。因此决定统计访问时长区间分别为 “[0-5>”, “[5-10>”, “[10-15>” 和 “15 or more” (单位:分钟)的会话数量,并以此绘制柱状图。
写一个SQL查询来报告(访问时长区间,会话总数)。结果可用任何顺序呈现。
展示效果:
+--------------+--------------+| bin | total |+--------------+--------------+| [0-5> | 3 || [5-10> | 1 || [10-15> | 0 || 15 or more | 1 |+--------------+--------------+对于 session_id 1,2 和 3 ,它们的访问时间大于等于 0 分钟且小于 5 分钟。对于 session_id 4,它的访问时间大于等于 5 分钟且小于 10 分钟。没有会话的访问时间大于等于 10 分钟且小于 15 分钟。对于 session_id 5, 它的访问时间大于等于 15 分钟。
Create table If Not Exists 89_Sessions (session_id int, duration int);Truncate table 89_Sessions;insert into 89_Sessions (session_id, duration) values ('1', '30');insert into 89_Sessions (session_id, duration) values ('2', '199');insert into 89_Sessions (session_id, duration) values ('3', '299');insert into 89_Sessions (session_id, duration) values ('4', '580');insert into 89_Sessions (session_id, duration) values ('5', '1000');
最终SQL:
-- 方法一select '[0-5>' as bin, count(*) as total from 89_Sessions where duration/60>=0 and duration/60<5unionselect '[5-10>' as bin, count(*) as total from 89_Sessions where duration/60>=5 and duration/60<10unionselect '[10-15>' as bin, count(*) as total from 89_Sessions where duration/60>=10 and duration/60<15unionselect '15 or more'as bin, count(*) as total from 89_Sessions where duration/60>=15-- 方法二select a.bin, count(b.bin) as totalfrom(select '[0-5>' as bin union select '[5-10>' as bin union select '[10-15>' as bin union select '15 or more' as bin)aleft join(select casewhen duration < 300 then '[0-5>'when duration >= 300 and duration < 600 then '[5-10>'when duration >= 600 and duration < 900 then '[10-15>'else '15 or more'end binfrom 89_Sessions)bon a.bin = b.bingroup by a.bin
90. 计算布尔表达式的值
写一个 SQL 查询, 以计算表 Expressions 中的布尔表达式,返回的结果表没有顺序要求.
展示效果:
+--------------+----------+---------------+-------+| left_operand | operator | right_operand | value |+--------------+----------+---------------+-------+| x | > | y | false || x | < | y | true || x | = | y | false || y | > | x | true || y | < | x | false || x | = | x | true |+--------------+----------+---------------+-------+
建表语句:
Create Table If Not Exists 90_Variables (name varchar(3), value int);Create Table If Not Exists 90_Expressions (left_operand varchar(3), operator ENUM('>', '<', '='), right_operand varchar(3));Truncate table 90_Variables;insert into 90_Variables (name, value) values ('x', '66');insert into 90_Variables (name, value) values ('y', '77');Truncate table 90_Expressions;insert into 90_Expressions (left_operand, operator, right_operand) values ('x', '>', 'y');insert into 90_Expressions (left_operand, operator, right_operand) values ('x', '<', 'y');insert into 90_Expressions (left_operand, operator, right_operand) values ('x', '=', 'y');insert into 90_Expressions (left_operand, operator, right_operand) values ('y', '>', 'x');insert into 90_Expressions (left_operand, operator, right_operand) values ('y', '<', 'x');insert into 90_Expressions (left_operand, operator, right_operand) values ('x', '=', 'x');
最终SQL:
selecte.left_operand,e.operator,e.right_operand,case e.operatorwhen '>' then if(v1.value>v2.value,'true','false')when '<' then if(v1.value<v2.value,'true','false')else if(v1.value=v2.value,'true','false')end valuefrom90_Expressions eleft join90_Variables v1onv1.name = e.left_operandleft join90_Variables v2onv2.name = e.right_operand;
91. 苹果和桔子
写一个 SQL 查询, 报告每一天 苹果 和 桔子 销售的数目的差异.返回的结果表, 按照格式为 (‘YYYY-MM-DD’) 的 sale_date 排序.
查询结果表如下例所示:
+------------+--------------+| sale_date | diff |+------------+--------------+| 2020-05-01 | 2 || 2020-05-02 | 0 || 2020-05-03 | 20 || 2020-05-04 | -1 |+------------+--------------+在 2020-05-01, 卖了 10 个苹果 和 8 个桔子 (差异为 10 - 8 = 2).在 2020-05-02, 卖了 15 个苹果 和 15 个桔子 (差异为 15 - 15 = 0).在 2020-05-03, 卖了 20 个苹果 和 0 个桔子 (差异为 20 - 0 = 20).在 2020-05-04, 卖了 15 个苹果 和 16 个桔子 (差异为 15 - 16 = -1).
Create table If Not Exists 91_Sales (sale_date date, fruit ENUM('apples', 'oranges'), sold_num int);Truncate table 91_Sales;insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-01', 'apples', '10');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-01', 'oranges', '8');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-02', 'apples', '15');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-02', 'oranges', '15');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-03', 'apples', '20');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-03', 'oranges', '0');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-04', 'apples', '15');insert into 91_Sales (sale_date, fruit, sold_num) values ('2020-05-04', 'oranges', '16');
-- 方法一selects1.sale_date,s1.sold_num - s2.sold_num as difffrom91_Sales s1join91_Sales s2ons1.sale_date = s2.sale_dateands1.fruit <> s2.fruitands1.fruit <> 'oranges';-- 方法二selectsale_date,sold_num - ld as difffrom(selectsale_date,sold_num,fruit,lead(sold_num ,1,null) over(partition by sale_date ) ldfrom 91_Sales )t1wherefruit='apples';
92. 活跃用户
写一个 SQL 查询, 找到活跃用户的 id 和 name,活跃用户是指那些至少连续 5 天登录账户的用户。返回的结果表按照 id 排序.
展示数据:
+----+----------+| id | name |+----+----------+| 7 | Jonathan |+----+----------+id = 1 的用户 Winston 仅仅在不同的 2 天内登录了 2 次, 所以, Winston 不是活跃用户.id = 7 的用户 Jonathon 在不同的 6 天内登录了 7 次, , 6 天中有 5 天是连续的, 所以, Jonathan 是活跃用户.
建表语句:
Create table If Not Exists 92_Accounts (id int, name varchar(10));Create table If Not Exists 92_Logins (id int, login_date date);Truncate table 92_Accounts;insert into 92_Accounts (id, name) values ('1', 'Winston');insert into 92_Accounts (id, name) values ('7', 'Jonathan');Truncate table 92_Logins;insert into 92_Logins (id, login_date) values ('7', '2020-05-30');insert into 92_Logins (id, login_date) values ('1', '2020-05-30');insert into 92_Logins (id, login_date) values ('7', '2020-05-31');insert into 92_Logins (id, login_date) values ('7', '2020-06-01');insert into 92_Logins (id, login_date) values ('7', '2020-06-02');insert into 92_Logins (id, login_date) values ('7', '2020-06-02');insert into 92_Logins (id, login_date) values ('7', '2020-06-03');insert into 92_Logins (id, login_date) values ('1', '2020-06-07');insert into 92_Logins (id, login_date) values ('7', '2020-06-10');
最终SQL:
-- 方法一selectdistinct a.id,a.namefrom92_Accounts a,92_logins l1wherea.id=l1.idand(selectcount(distinct l2.login_date)from92_logins l2wherel1.id=l2.idanddatediff(l1.login_date,l2.login_date) between 0 and 4)>=5order by id;-- 方法二selectdistinct a.id, a.namefrom92_Accounts ajoin92_Logins l1using(id)join92_Logins l2onl1.id = l2.idanddatediff(l2.login_date, l1.login_date) between 0 and 4group bya.id, a.name, l1.login_datehavingcount(distinct l2.login_date) = 5;-- 方法三selectt3.id,namefrom(selectdistinct idfrom(selectid,login_date,lead(login_date,4,null) over(partition by id order by login_date) ldfrom(selectid,login_datefrom92_Loginsgroup byid,login_date)t1)t2where datediff(ld,login_date)=4)t3left join92_Accounts aont3.id = a.id;
93. 矩形面积
写一个 SQL 语句, 报告由表中任意两点可以形成的所有可能的矩形.
结果表中的每一行包含三列 (p1, p2, area) 如下:
- p1 和 p2 是矩形两个对角的 id 且 p1 < p2.
- 矩形的面积由列 area 表示.
请按照面积大小降序排列,如果面积相同的话, 则按照 p1 和 p2 升序对结果表排序
+----------+-------------+-------------+| p1 | p2 | area |+----------+-------------+-------------+| 2 | 3 | 6 || 1 | 2 | 2 |+----------+-------------+-------------+p1 应该小于 p2 并且面积大于 0.p1 = 1 且 p2 = 2 时, 面积等于 |2-4| * |8-7| = 2.p1 = 2 且 p2 = 3 时, 面积等于 |4-2| * |7-10| = 6.p1 = 1 且 p2 = 3 时, 是不可能为矩形的, 因为面积等于 0.
Create table If Not Exists 93_Points (id int, x_value int, y_value int);Truncate table 93_Points;insert into 93_Points (id, x_value, y_value) values ('1', '2', '8');insert into 93_Points (id, x_value, y_value) values ('2', '4', '7');insert into 93_Points (id, x_value, y_value) values ('3', '2', '10');
最终SQL:
selecta.id P1,b.id P2,abs(a.x_value-b.x_value)*abs(a.y_value-b.y_value) as areafromPoints a,Points bwherea.id<b.idanda.x_value != b.x_valueanda.y_value != b.y_valueorder byarea desc,P1 ,P2
94. 计算税后工资
写一条查询 SQL 来查找每个员工的税后工资
每个公司的税率计算依照以下规则
- 如果这个公司员工最高工资不到 1000 ,税率为 0%
- 如果这个公司员工最高工资在 1000 到 10000 之间,税率为 24%
- 如果这个公司员工最高工资大于 10000 ,税率为 49%
按任意顺序返回结果,税后工资结果取整
结果表格式如下例所示:
+------------+-------------+---------------+--------+| company_id | employee_id | employee_name | salary |+------------+-------------+---------------+--------+| 1 | 1 | Tony | 1020 || 1 | 2 | Pronub | 10863 || 1 | 3 | Tyrrox | 5508 || 2 | 1 | Pam | 300 || 2 | 7 | Bassem | 450 || 2 | 9 | Hermione | 700 || 3 | 7 | Bocaben | 76 || 3 | 2 | Ognjen | 1672 || 3 | 13 | Nyancat | 2508 || 3 | 15 | Morninngcat | 5911 |+------------+-------------+---------------+--------+对于公司 1 ,最高工资是 21300 ,其每个员工的税率为 49%对于公司 2 ,最高工资是 700 ,其每个员工税率为 0%对于公司 3 ,最高工资是 7777 ,其每个员工税率是 24%税后工资计算 = 工资 - ( 税率 / 100)*工资对于上述案例,Morninngcat 的税后工资 = 7777 - 7777 * ( 24 / 100) = 7777 - 1866.48 = 5910.52 ,取整为 5911
Create table If Not Exists 94_Salaries (company_id int, employee_id int, employee_name varchar(13), salary int);
Truncate table 94_Salaries;
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('1', '1', 'Tony', '2000');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('1', '2', 'Pronub', '21300');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('1', '3', 'Tyrrox', '10800');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('2', '1', 'Pam', '300');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('2', '7', 'Bassem', '450');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('2', '9', 'Hermione', '700');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('3', '7', 'Bocaben', '100');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('3', '2', 'Ognjen', '2200');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('3', '13', 'Nyancat', '3300');
insert into 94_Salaries (company_id, employee_id, employee_name, salary) values ('3', '15', 'Morninngcat', '7777');
最终SQL:
-- 方法一
select
s1.company_id,
s1.employee_id,
s1.employee_name,
round(case
when m.max_salary<1000 then salary
when m.maxsalary<10000 then salary*(1-0.24)
else salary*(1-0.49)
end ,0) salary
from
94_Salaries s1
left join
(select
s2.company_id,
max(s2.salary) max_salary
from
94_Salaries s2
group by
company_id
) m
on
m.company_id = s1.conpany_id;
-- 方法二
select
company_id,
employee_id,
employee_name,
round(case
when maxsalary<1000 then salary
when maxsalary<10000 then salary*(1-0.24)
else salary*(1-0.49)
end ,0) salary
from
(select
*,
max(salary) over(partition by company_id ) maxsalary
from Salaries )t1 ;
95. 周内每天的销售情况
写一个SQL语句,报告 周内每天 每个商品类别下订购了多少单位。返回结果表单 按商品类别排序 。
查询结果格式如下例所示
+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| Category | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| Book | 20 | 5 | 0 | 0 | 10 | 0 | 0 |
| Glasses | 0 | 0 | 0 | 0 | 5 | 0 | 0 |
| Phone | 0 | 0 | 5 | 1 | 0 | 0 | 10 |
| T-Shirt | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
在周一(2020-06-01, 2020-06-08),Book分类(ids: 1, 2)下,总共销售了20个单位(10 + 10)
在周二(2020-06-02),Book分类(ids: 1, 2)下,总共销售了5个单位
在周三(2020-06-03),Phone分类(ids: 3, 4)下,总共销售了5个单位
在周四(2020-06-04),Phone分类(ids: 3, 4)下,总共销售了1个单位
在周五(2020-06-05),Book分类(ids: 1, 2)下,总共销售了10个单位,Glasses分类(ids: 5)下,总共销售了5个单位
在周六, 没有商品销售
在周天(2020-06-14, 2020-06-21),Phone分类(ids: 3, 4)下,总共销售了10个单位(5 + 5)
没有销售 T-Shirt 类别的商品
Create table If Not Exists 95_Orders (order_id int, customer_id int, order_date date, item_id varchar(30), quantity int);
Create table If Not Exists 95_Items (item_id varchar(30), item_name varchar(30), item_category varchar(30));
Truncate table 95_Orders;
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('1', '1', '2020-06-01', '1', '10');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('2', '1', '2020-06-08', '2', '10');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('3', '2', '2020-06-02', '1', '5');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('4', '3', '2020-06-03', '3', '5');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('5', '4', '2020-06-04', '4', '1');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('6', '4', '2020-06-05', '5', '5');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('7', '5', '2020-06-05', '1', '10');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('8', '5', '2020-06-14', '4', '5');
insert into 95_Orders (order_id, customer_id, order_date, item_id, quantity) values ('9', '5', '2020-06-21', '3', '5');
Truncate table 95_Items;
insert into 95_Items (item_id, item_name, item_category) values ('1', 'LC Alg. Book', 'Book');
insert into 95_Items (item_id, item_name, item_category) values ('2', 'LC DB. Book', 'Book');
insert into 95_Items (item_id, item_name, item_category) values ('3', 'LC SmarthPhone', 'Phone');
insert into 95_Items (item_id, item_name, item_category) values ('4', 'LC Phone 2020', 'Phone');
insert into 95_Items (item_id, item_name, item_category) values ('5', 'LC SmartGlass', 'Glasses');
insert into 95_Items (item_id, item_name, item_category) values ('6', 'LC T-Shirt XL', 'T-shirt');
最终SQL:
select
item_category as category,
sum(case when num = 2 then quantity else 0 end) as Monday,
sum(case when num = 3 then quantity else 0 end) as Tuesday,
sum(case when num = 4 then quantity else 0 end) as Wednesday,
sum(case when num = 5 then quantity else 0 end) as Thursday,
sum(case when num = 6 then quantity else 0 end) as Friday,
sum(case when num = 7 then quantity else 0 end) as Saturday,
sum(case when num = 1 then quantity else 0 end) as Sunday
from
(select
item_category,
quantity,
dayofweek(order_date) as num
from
95_items i
left join
95_orders o
on
i.item_id=o.item_id) t
group by
item_category
order by
item_category;
96. 按日期分组销售产品
编写一个 SQL 查询来查找每个日期、销售的不同产品的数量及其名称。
每个日期的销售产品名称应按词典序排列。
返回按 sell_date 排序的结果表。
查询结果格式如下例所示。
+------------+----------+------------------------------+
| sell_date | num_sold | products |
+------------+----------+------------------------------+
| 2020-05-30 | 3 | Basketball,Headphone,T-shirt |
| 2020-06-01 | 2 | Bible,Pencil |
| 2020-06-02 | 1 | Mask |
+------------+----------+------------------------------+
对于2020-05-30,出售的物品是 (Headphone, Basketball, T-shirt),按词典序排列,并用逗号 ',' 分隔。
对于2020-06-01,出售的物品是 (Pencil, Bible),按词典序排列,并用逗号分隔。
对于2020-06-02,出售的物品是 (Mask),只需返回该物品名。
建表语句:
Create table If Not Exists 96_Activities (sell_date date, product varchar(20));
Truncate table 96_Activities;
insert into 96_Activities (sell_date, product) values ('2020-05-30', 'Headphone');
insert into 96_Activities (sell_date, product) values ('2020-06-01', 'Pencil');
insert into 96_Activities (sell_date, product) values ('2020-06-02', 'Mask');
insert into 96_Activities (sell_date, product) values ('2020-05-30', 'Basketball');
insert into 96_Activities (sell_date, product) values ('2020-06-01', 'Bible');
insert into 96_Activities (sell_date, product) values ('2020-06-02', 'Mask');
insert into 96_Activities (sell_date, product) values ('2020-05-30', 'T-Shirt');
最终SQL:
select
sell_date,
count(distinct product) num_sold,
group_concat(distinct product order by product) products
from
Activities
group by
sell_date;
97. 上月播放的儿童适宜电影
写一个 SQL 语句, 报告在 2020 年 6 月份播放的儿童适宜电影的去重电影名.返回的结果表单没有顺序要求.
查询结果的格式如下例所示.
+--------------+
| title |
+--------------+
| Aladdin |
+--------------+
"Leetcode Movie" 是儿童不宜的电影.
"Alg. for Kids" 不是电影.
"Database Sols" 不是电影
"Alladin" 是电影, 儿童适宜, 并且在 2020 年 6 月份播放.
"Cinderella" 不在 2020 年 6 月份播放.
Create table If Not Exists 97_TVProgram (program_date date, content_id int, channel varchar(30));
Create table If Not Exists 97_Content (content_id varchar(30), title varchar(30), Kids_content ENUM('Y', 'N'), content_type varchar(30));
Truncate table 97_TVProgram;
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-06-10 08:00', '1', 'LC-Channel');
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-05-11 12:00', '2', 'LC-Channel');
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-05-12 12:00', '3', 'LC-Channel');
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-05-13 14:00', '4', 'Disney Ch');
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-06-18 14:00', '4', 'Disney Ch');
insert into 97_TVProgram (program_date, content_id, channel) values ('2020-07-15 16:00', '5', 'Disney Ch');
Truncate table 97_Content;
insert into 97_Content (content_id, title, Kids_content, content_type) values ('1', 'Leetcode Movie', 'N', 'Movies');
insert into 97_Content (content_id, title, Kids_content, content_type) values ('2', 'Alg. for Kids', 'Y', 'Series');
insert into 97_Content (content_id, title, Kids_content, content_type) values ('3', 'Database Sols', 'N', 'Series');
insert into 97_Content (content_id, title, Kids_content, content_type) values ('4', 'Aladdin', 'Y', 'Movies');
insert into 97_Content (content_id, title, Kids_content, content_type) values ('5', 'Cinderella', 'Y', 'Movies');
最终SQL:
select
distinct title
from
97_TVProgram t
left join
97_Content c
on
t.content_id = c.content_id
where
Kids_content ='Y'
and
date_format(program_date ,'%Y-%m')='2020-06'
and
content_type='Movies';
98. 可以放心投资的国家
写一段 SQL, 找到所有该公司可以投资的国家(该国的平均通话时长要严格地大于全球平均通话时长).返回的结果表没有顺序要求.
查询的结果格式如下例所示.
+----------+
| country |
+----------+
| Peru |
+----------+
国家Peru的平均通话时长是 (102 + 102 + 330 + 330 + 5 + 5) / 6 = 145.666667
国家Israel的平均通话时长是 (33 + 4 + 13 + 13 + 3 + 1 + 1 + 7) / 8 = 9.37500
国家Morocco的平均通话时长是 (33 + 4 + 59 + 59 + 3 + 7) / 6 = 27.5000
全球平均通话时长 = (2 * (33 + 3 + 59 + 102 + 330 + 5 + 13 + 3 + 1 + 7)) / 20 = 55.70000
所以, Peru是唯一的平均通话时长大于全球平均通话时长的国家, 也是唯一的推荐投资的国家.
Create table If Not Exists 98_Person (id int, name varchar(15), phone_number varchar(11));
Create table If Not Exists 98_Country (name varchar(15), country_code varchar(3));
Create table If Not Exists 98_Calls (caller_id int, callee_id int, duration int);
Truncate table 98_Person;
insert into 98_Person (id, name, phone_number) values ('3', 'Jonathan', '051-1234567');
insert into 98_Person (id, name, phone_number) values ('12', 'Elvis', '051-7654321');
insert into 98_Person (id, name, phone_number) values ('1', 'Moncef', '212-1234567');
insert into 98_Person (id, name, phone_number) values ('2', 'Maroua', '212-6523651');
insert into 98_Person (id, name, phone_number) values ('7', 'Meir', '972-1234567');
insert into 98_Person (id, name, phone_number) values ('9', 'Rachel', '972-0011100');
Truncate table 98_Country;
insert into 98_Country (name, country_code) values ('Peru', '051');
insert into 98_Country (name, country_code) values ('Israel', '972');
insert into 98_Country (name, country_code) values ('Morocco', '212');
insert into 98_Country (name, country_code) values ('Germany', '049');
insert into 98_Country (name, country_code) values ('Ethiopia', '251');
Truncate table 98_Calls;
insert into 98_Calls (caller_id, callee_id, duration) values ('1', '9', '33');
insert into 98_Calls (caller_id, callee_id, duration) values ('2', '9', '4');
insert into 98_Calls (caller_id, callee_id, duration) values ('1', '2', '59');
insert into 98_Calls (caller_id, callee_id, duration) values ('3', '12', '102');
insert into 98_Calls (caller_id, callee_id, duration) values ('3', '12', '330');
insert into 98_Calls (caller_id, callee_id, duration) values ('12', '3', '5');
insert into 98_Calls (caller_id, callee_id, duration) values ('7', '9', '13');
insert into 98_Calls (caller_id, callee_id, duration) values ('7', '1', '3');
insert into 98_Calls (caller_id, callee_id, duration) values ('9', '7', '1');
insert into 98_Calls (caller_id, callee_id, duration) values ('1', '7', '7');
最终SQL:
-- 方法一
select
c2.name as country
from
98_Calls c1,
98_Person p,
98_Country c2
where
(p.id=c1.caller_id or p.id=c1.callee_id)
and
c2.country_code=left(p.phone_number,3)
group by
c2.name
having
avg(duration)>(select avg(duration) from 98_Calls);
99. 消费者下单频率
写一个 SQL 语句, 报告消费者的 id 和名字, 其中消费者在 2020 年 6 月和 7 月, 每月至少花费了$100.结果表无顺序要求.
查询结果格式如下例所示.
+--------------+------------+
| customer_id | name |
+--------------+------------+
| 1 | Winston |
+--------------+------------+
Winston 在2020年6月花费了$300(300 * 1), 在7月花费了$100(10 * 1 + 45 * 2).
Jonathan 在2020年6月花费了$600(300 * 2), 在7月花费了$20(2 * 10).
Moustafa 在2020年6月花费了$110 (10 * 2 + 45 * 2), 在7月花费了$0.
建表语句:
Create table If Not Exists 99_Customers (customer_id int, name varchar(30), country varchar(30));
Create table If Not Exists 99_Product (product_id int, description varchar(30), price int);
Create table If Not Exists 99_Orders (order_id int, customer_id int, product_id int, order_date date, quantity int);
Truncate table 99_Customers;
insert into 99_Customers (customer_id, name, country) values ('1', 'Winston', 'USA');
insert into 99_Customers (customer_id, name, country) values ('2', 'Jonathan', 'Peru');
insert into 99_Customers (customer_id, name, country) values ('3', 'Moustafa', 'Egypt');
Truncate table 99_Product;
insert into 99_Product (product_id, description, price) values ('10', 'LC Phone', '300');
insert into 99_Product (product_id, description, price) values ('20', 'LC T-Shirt', '10');
insert into 99_Product (product_id, description, price) values ('30', 'LC Book', '45');
insert into 99_Product (product_id, description, price) values ('40', 'LC Keychain', '2');
Truncate table 99_Orders;
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('1', '1', '10', '2020-06-10', '1');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('2', '1', '20', '2020-07-01', '1');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('3', '1', '30', '2020-07-08', '2');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('4', '2', '10', '2020-06-15', '2');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('5', '2', '40', '2020-07-01', '10');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('6', '3', '20', '2020-06-24', '2');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('7', '3', '30', '2020-06-25', '2');
insert into 99_Orders (order_id, customer_id, product_id, order_date, quantity) values ('9', '3', '30', '2020-05-08', '3');
最终SQL:
select
customer_id,name
from
Customers
where
customer_id in (select
customer_id
from
(select
customer_id,
month(order_date) as month,
sum(quantity*price) as total
from
Orders o
left join
Product p
on
o.product_id = p.product_id
where
month(order_date) = 6 or month(order_date)=7
group by
customer_id,month(order_date)
) as t1
where
total >=100
group by
customer_id
having
count(*)>=2 );
100. 查找拥有有效邮箱的用户
Write an SQL query to find the users who have valid emails.
A valid e-mail has a prefix name and a domain where:
- The prefix name is a string that may contain letters (upper or lower case), digits, underscore
'_', period'.'and/or dash'-'. The prefix name must start with a letter. - The domain is
'@leetcode.com'.
Return the result table in any order.
The query result format is in the following example.
+---------+-----------+-------------------------+
| user_id | name | mail |
+---------+-----------+-------------------------+
| 1 | Winston | winston@leetcode.com |
| 3 | Annabelle | bella-@leetcode.com |
| 4 | Sally | sally.come@leetcode.com |
+---------+-----------+-------------------------+
The mail of user 2 doesn't have a domain.
The mail of user 5 has # sign which is not allowed.
The mail of user 6 doesn't have leetcode domain.
The mail of user 7 starts with a period.
建表语句:
Create table If Not Exists 100_Users (user_id int, name varchar(30), mail varchar(50));
Truncate table 100_Users;
insert into 100_Users (user_id, name, mail) values ('1', 'Winston', 'winston@leetcode.com');
insert into 100_Users (user_id, name, mail) values ('2', 'Jonathan', 'jonathanisgreat');
insert into 100_Users (user_id, name, mail) values ('3', 'Annabelle', 'bella-@leetcode.com');
insert into 100_Users (user_id, name, mail) values ('4', 'Sally', 'sally.come@leetcode.com');
insert into 100_Users (user_id, name, mail) values ('5', 'Marwan', 'quarz#2020@leetcode.com');
insert into 100_Users (user_id, name, mail) values ('6', 'David', 'david69@gmail.com');
insert into 100_Users (user_id, name, mail) values ('7', 'Shapiro', '.shapo@leetcode.com');
最终SQL:
SELECT
*
FROM
100_Users
WHERE
mail REGEXP '^[a-zA-Z]+[\\w_\\.\\-]*@leetcode.com$'
ORDER BY
user_id;
