【MySQL LeetCode】102题学习整理中


1. 重复的电子邮件:

编写一个解决方案来报告所有重复的电子邮件。请注意,保证电子邮件字段不为 NULL。以任意顺序返回结果表。结果格式如下例所示。
示例1:
输入:
Person table:

idemail
1a@b.com
2c@d.com
3a@b.com

输出:

Email
a@b.com

解释: a@b.com is repeated two times.

解决方案:

SELECT email
FROM person
GROUP BY email
HAVING COUNT(*) > 1;

2. 游戏玩法分析

活动表 (Activity)

Column NameType
player_idint
device_idint
event_datedate
games_playedint

在 SQL 中,表的主键是 (player_id, event_date)

这张表展示了一些游戏玩家在游戏平台上的行为活动。每行数据记录了一名玩家在退出平台之前,当天使用同一台设备登录平台后打开的游戏的数目(可能是 0 个)。

查询每位玩家第一次登录平台的日期。

示例1:

Activity 表:

player_iddevice_idevent_dategames_played
122016-03-015
122016-05-026
232017-06-251
312016-03-020
342018-07-035

结果表:

player_idfirst_login
12016-03-01
22017-06-25
32016-03-02

解决方案

SELECT player_id, MIN(event_date) AS first_login
FROM activity
GROUP BY player_id;

3. 获得最高回答率问题

从具有以下列的表 survey_log 中获取回答率最高的问题:uidactionquestion_idanswer_idq_numtimestamp

  • uid 表示用户 ID;
  • action 有以下几种值:showanswerskip
  • action列为answeranswer_id不为null,而showskipnull
  • q_num 是当前会话中问题的数字顺序。
    编写一个sql查询来找出回答率最高的问题。

Input:

uidactionquestion_idanswer_idq_numtimestamp
5show285null1123
5answer2851241241124
5show369null2125
5skip369null2126

Output:

survey_log
285

Explanation:
问题 285 的答对率为 1/1,而问题 369 的答对率为 0/1,因此输出结果为 285。

解决方案

SELECT TOP 1 question_id AS survey_log
FROM survey_log
GROUP BY question_id
ORDER BY COUNT(answer_id)*1.0/(COUNT(*)-COUNT(answer_id)) DESC;

4. 寻找客户推荐人

Table: Customer

Column NameType
idint
namevarchar
referee_idint

在 SQL 中,"id "是该表的主键列。表中的每一行都显示客户的 id 、客户的 name 和推荐客户的 id

查找不是由客户通过 id = 2 引用的客户姓名。以任意顺序返回结果表。结果格式如下例所示。

示例 1:

Input:

Customer table:

idnamereferee_id
1Willnull
2Janenull
3Alex2
4Billnull
5Zack1
6Mark2

Output:

name
Will
Jane
Bill
Zack

解决方案

-- Solution 1: Basics
SELECT name 
FROM customer
WHERE ISNULL(referee_id,0) != 2;


-- Solution 2: Basics
SELECT name 
FROM customer
WHERE COALESCE(referee_id,0) != 2;


-- Solution 3: Basics
SELECT name
FROM customer
WHERE referee_id != 2 OR referee_id IS NULL;

5. 下单数量最多的顾客

Table: Orders

Column NameType
order_numberint
customer_numberint

order_number 是该表的主键(具有唯一值的列)。该表包含有关订单 ID 和客户 ID 的信息。

编写一个解决方案来查找下订单数量最多的客户的 customer_number 。生成测试用例是为了确保一个客户下的订单比任何其他客户都多。结果格式如下例所示。

示例1:

Input:

Orders table:

order_numbercustomer_number
11
22
33
43

Output:

customer_number
3

Explanation:

编号为 3 的客户有两个订单,大于客户 1 或客户 2,因为他们每人只有一个订单。因此,结果是 “客户编号 3”。

追问:
如果不止一个客户的订单数量最多,在这种情况下,您能找到所有的 `客户编号’吗?

解决方案

SELECT TOP 1 customer_number
FROM orders
GROUP BY customer_number
ORDER BY COUNT(*) DESC;

6. 大国

Table: World

Column NameType
namevarchar
continentvarchar
areaint
populationint
gdpbigint

name "是该表的主键(具有唯一值的列)。该表的每一行都提供了一个国家的名称、所属大洲、面积、人口和 GDP 值等信息。

如果出现以下情况,一个国家就是大国

  1. 面积至少有 300 万(即 3000000 平方公里),或
  2. 人口至少有两千五百万(即 25000000)。

写出一个解决方案,找出大国的名称、人口和面积。按任意顺序返回结果表。
结果格式见下例。

示例 1 :

Input:

World table:

namecontinentareapopulationgdp
AfghanistanAsia6522302550010020343000000
AlbaniaEurope28748283174112960000000
AlgeriaAfrica238174137100000188681000000
AndorraEurope468781153712000000
AngolaAfrica124670020609294100990000000

Output:

namepopulationarea
Afghanistan25500100652230
Algeria371000002381741

解决方案

SELECT name, population, area
FROM World
WHERE area > 3000000 OR population > 25000000;

7. 超过 5 名学生的班级

Table: Courses

Column NameType
studentvarchar
classvarchar

(student, class) 是此表的主键(具有唯一值的列组合)。该表的每一行都显示了学生的姓名和所在班级。

写出一个解决方案,找出所有至少有 5 名学生的班级。以任意顺序返回结果表。结果格式如下例所示。

示例 1:

Input:

Courses table:

studentclass
AMath
BEnglish
CMath
DBiology
EMath
FComputer
GMath
HMath
IMath

Output:

class
Math

Explanation:

  • 数学有 6 名学生,因此我们将其包括在内。
  • 英语有 1 名学生,所以不包括在内。
  • 生物有 1 名学生,因此我们不将其包括在内。
  • 计算机有 1 名学生,因此不包括在内。

解决方案

SELECT class
FROM courses
GROUP BY class
HAVING COUNT(DISTINCT student) >= 5;

8. 最大的单个数字

Table: MyNumbers

Column NameType
numint

该表可能包含重复数据(换句话说,该表在 SQL 中没有主键)。该表的每一行都包含一个整数。

单一数字是指只在 MyNumbers 表中出现过一次的数字。找出最大的单个数字。如果没有单个数字,则报告 null。结果格式如下例所示。

示例1 :

Input:

MyNumbers table:

num
8
8
3
3
1
4
5
6

Output:

num
6

Explanation:
单个数字是 1、4、5 和 6。
由于 6 是最大的单个数字,因此我们返回它。

示例 2 :

Input:

MyNumbers table:

num
8
8
7
7
3
3
3

Output:

num
null

Explanation:
输入表中没有单个数字,因此我们返回 null

解决方案

SELECT MAX(num) AS num
FROM (
    -- Select numbers appear only once
    SELECT num 
    FROM my_numbers 
    GROUP BY num 
    HAVING COUNT(*) = 1
) tb1;

9. 不无聊的电影

Table: Cinema

| Column Name | Type |
|加粗样式-------------|---------|
| id | int |
| movie | varchar |
| description | varchar |
| rating | float |

id 是该表的主键(具有唯一值的列)。每一行都包含电影名称、类型和评分信息。rating是一个小数点后 2 位的浮点数,取值范围为 [0, 10] 。

编写一个解决方案,报告 ID 为奇数且描述不 "无聊 "的电影。返回按评分降序排列的结果表。结果格式如下例所示。

示例 1:

Input:

Cinema table:

idmoviedescriptionrating
1Wargreat 3D8.9
2Sciencefiction8.5
3irishboring6.2
4Ice songFantacy8.6
5House cardInteresting9.1

Output:

idmoviedescriptionrating
5House cardInteresting9.1
1Wargreat 3D8.9

Explanation:
我们有三部 ID 为奇数的电影:1、3 和 5。ID = 3 的电影很无聊,因此我们不将其列入答案。

解决方案

SELECT *
FROM cinema
WHERE id % 2 = 1 AND description != 'boring'
ORDER BY rating DESC;

10. 至少合作三次的演员和导演

Table: ActorDirector

Column NameType
actor_idint
director_idint
timestampint

timestamp是该表的主键(具有唯一值的列)。写一个解决方案,找出演员与导演至少合作过三次的所有配对(actor_id, director_id)。按任意顺序返回结果表。结果格式如下例所示。

示例 1:

Input:
ActorDirector table:

actor_iddirector_idtimestamp
110
111
112
123
124
215
216

Output:

actor_iddirector_id
11

Explanation:
唯一的一对是(1,1),他们正好合作了 3 次。

解决方案

SELECT actor_id, director_id
FROM ActorDirector
GROUP BY actor_id, director_id
HAVING COUNT(*) >= 3;

11. 产品销售分析

Table: Sales

Column NameType
sale_idint
product_idint
yearint
quantityint
priceint

sale_id 是该表的主键。product_id是 "Product"表的外键。请注意,price是按单位计算的。

Table: Product

Column NameType
product_idint
product_namevarchar

product_id 是该表的主键。编写一条 SQL 查询,报告每个产品 ID 的总销售量。查询结果格式如下:

Sales table:

sale_idproduct_idyearquantityprice
11002008105000
21002009125000
72002011159000

Product table:

product_idproduct_name
100Nokia
200Apple
300Samsung

Result table:

product_idtotal_quantity
10022
20015

解决方案

SELECT product_id, SUM(quantity) AS total_quantity
FROM Sales
GROUP BY product_id;

12. 项目员工

Table: Project

Column NameType
project_idint
employee_idint

(project_id,employee_id)是该表的主键。
employee_idEmployee 表的外键。

Table: Employee

Column NameType
employee_idint
namevarchar
experience_yearsint

employee_id 是该表的主键。编写一个 SQL 查询,报告所有拥有最多雇员的项目。查询结果格式如下:

Project table:

project_idemployee_id
11
12
13
21
24

Employee table:

employee_idnameexperience_years
1Khaled3
2Ali2
3John1
4Doe2

Result table:

project_id
1

第一个项目有 3 名员工,第二个项目有 2 名员工,因此第一个项目是员工人数最多的项目。

解决方案

SELECT TOP 1 WITH TIES project_id
FROM Project
GROUP BY project_id
ORDER BY COUNT(employee_id) DESC;

13. 销售分析

Table: Product

Column NameType
product_idint
product_namevarchar
unit_priceint

product_id是该表的主键。

Table: Sales

Column NameType
seller_idint
product_idint
buyer_idint
sale_datedate
quantityint
priceint

该表没有主键,可以有重复行。product_idProduct表的外键。

编写一个 SQL 查询,按总销售价格报告最畅销的产品。如果出现并列,则全部报告。查询结果格式如下:

Product table:

product_idproduct_nameunit_price
1S81000
2G4800
3iPhone1400

Sales table:

seller_idproduct_idbuyer_idsale_datequantityprice
1112019-01-2122000
1222019-02-171800
2232019-06-021800
3342019-05-1322800

Result table:

seller_id
1
3

id为 1 和 3 的卖家都卖出了总价最高的 2800 件产品。

解决方案

SELECT TOP 1 WITH TIES seller_id
FROM Sales
GROUP BY seller_id
ORDER BY SUM(price) DESC;

14. 过去 30 天的用户活动

Table: Activity

Column NameType
user_idint
session_idint
activity_datedate
activity_typeenum

此表可能有重复行。
activity_type 列是一个 ENUM(类别)类 (open_session, end_session, scroll_down, send_message).
该表显示了一个社交媒体网站的用户活动。
请注意,每个会话只属于一个用户。

写一个解决方案,找出截至 2019-07-27 日(含)的 30 天内的每日活跃用户数。如果用户在某天至少进行了一次活动,则该用户在该天为活跃用户。以任意顺序返回结果表。结果格式如下例所示。

示例 1:

Input:
Activity table:

user_idsession_idactivity_dateactivity_type
112019-07-20open_session
112019-07-20scroll_down
112019-07-20end_session
242019-07-20open_session
242019-07-21send_message
242019-07-21end_session
322019-07-21open_session
322019-07-21send_message
322019-07-21end_session
432019-06-25open_session
432019-06-25end_session

Output:

dayactive_users
2019-07-202
2019-07-212

Explanation:
请注意,我们并不关心活跃用户为零的天数。

解决方案

SELECT activity_date AS day, COUNT(DISTINCT user_id) AS active_users
FROM Activity
GROUP BY activity_date
HAVING activity_date BETWEEN  DATEADD(day,-29,'2019-07-27') and '2019-07-27';

15. 文章浏览量

Table: Views

Column NameType
article_idint
author_idint
viewer_idint
view_datedate

该表没有主键(具有唯一值的列),因此可能有重复行。
该表中的每一行都表示某个读者在某个日期浏览了某篇文章(由某个作者撰写)。
请注意,相同的 author_idviewer_id 表示同一个人。

写一个解决方案,找出所有至少浏览过一篇自己文章的作者。返回按 id 升序排序的结果表。结果格式如下。

示例 1:

Input:
Views table:

article_idauthor_idviewer_idview_date
1352019-08-01
1362019-08-02
2772019-08-01
2762019-08-02
4712019-07-22
3442019-07-21
3442019-07-21

Output:

id
4
7

解决方案

SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY id;

16. 文章浏览量

Table: Views

Column NameType
article_idint
author_idint
viewer_idint
view_datedate

该表没有主键,可能有重复行。该表中的每一行都表示某个读者在某个日期浏览了某篇文章(由某个作者撰写)。请注意,相同的 author_idviewer_id 表示同一个人。

编写一条 SQL 查询,找出所有在同一日期浏览过一篇以上文章的人,并按其 id 升序排序。查询结果格式如下:

Views table:

article_idauthor_idviewer_idview_date
1352019-08-01
3452019-08-01
1362019-08-02
2772019-08-01
2762019-08-02
4712019-07-22
3442019-07-21
3442019-07-21

Result table:

id
5
6

ID 为 5 和 6 的用户在 2019-08-01 浏览了不止一篇文章。

解决方案

SELECT DISTINCT viewer_id AS id
FROM Views
GROUP BY viewer_id, view_date
-- When viewer viewed the same article more than once in the same day, using DISTINCT could avoid count that article twice
HAVING COUNT(DISTINCT article_id) > 1
ORDER BY id;

17. 删除重复邮件

Table: Person

Column NameType
idint
emailvarchar

id 是该表的主键(具有唯一值的列)。
该表的每一行都包含一个电子邮件。电子邮件不包含大写字母。

请编写一个解决方案,删除所有重复的电子邮件,只保留一个具有最小 id 的唯一电子邮件。

对于 SQL 用户,请注意应编写 DELETE 语句,而不是 SELECT 语句。

个人表的最终顺序并不重要。

结果格式如下例所示。

示例 1:

Input:
Person table:

idemail
1john@example.com
2bob@example.com
3john@example.com

Output:

idemail
1john@example.com
2bob@example.com

Explanation:
john@example.com 重复两次。我们保留最小 Id = 1 的一行。

解决方案

-- Solution 1: SQL Command, Join
DELETE p1 
FROM person p1
JOIN person p2
    ON p1.email = p2.email AND p1.id > p2.id;  
    


-- Solution 2: SQL Command, Subquery
DELETE FROM person
WHERE id NOT IN (
    SELECT *
    FROM (
        SELECT MIN(id) AS id
        FROM person
        GROUP BY email
        ) tb1
);

18. 交换工资

Table: Salary

Column NameType
idint
namevarchar
sexENUM
salaryint

id 是该表的主键(具有唯一值的列)。
sex 列是类型为('m', 'f')的 ENUM(类别)值。
该表包含一名雇员的信息。

编写一个解决方案,用一条更新语句交换所有的 "f "和 "m "值(即把所有的 "f "值改为 “m”,反之亦然),并且不使用中间临时表。请注意,您必须编写一条更新语句,不要为这个问题编写任何选择语句。结果格式如下例所示。

示例 1:

Input:
Salary table:

idnamesexsalary
1Am2500
2Bf1500
3Cm5500
4Df500

Output:

idnamesexsalary
1Af2500
2Bm1500
3Cf5500
4Dm500

Explanation:
(1、A)和(3、C)中的 "m "改为 “f”。
(2、B)和(4、D)中的 "f "改为 “m”。

解决方案

UPDATE salary
SET sex = CASE WHEN sex = 'm' THEN 'f' ELSE 'm' END;

19. 组合两个表

表: Person

列名类型
PersonIdint
FirstNamevarchar
LastNamevarchar

personId 是该表的主键(具有唯一值的列)。该表包含一些人的 ID 和他们的姓和名的信息。

表: Address

列名类型
AddressIdint
PersonIdint
Cityvarchar
Statevarchar

addressId 是该表的主键(具有唯一值的列)。该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息。

编写解决方案,报告 Person 表中每个人的姓、名、城市和州。如果 personId 的地址不在 Address 表中,则报告为 null 。以 任意顺序 返回结果表。结果格式如下所示。

示例 1:

输入:

Person表:

personIdlastNamefirstName
1WangAllen
2AliceBob

Address表:

addressIdpersonIdcitystate
12New York CityNew York
23LeetcodeCalifornia

输出:

firstNamelastNamecitystate
AllenWangNullNull
BobAliceNew York CityNew York

解释:
地址表中没有 personId = 1 的地址,所以它们的城市和州返回 null。addressId = 1 包含了 personId = 2 的地址信息。

解决方案

SELECT p.firstname, p.lastname, a.city, a.state
FROM person p
-- LEFT JOIN return all records from the left table, and the matched records from the right table
LEFT JOIN address a
  ON p.personid = a.personid;

20. 找出薪水比经理高的员工

Table: Employee

Column NameType
idint
namevarchar
salaryint
managerIdint

id 是该表的主键(具有唯一值的列)。该表的每一行都包含员工的 ID、姓名、工资及其经理的 ID。

编写一个解决方案,找出收入高于其经理的员工。按任意顺序返回结果表。结果格式如下例所示。

例 1:

Input:
Employee table:

idnamesalarymanagerId
1Joe700003
2Henry800004
3Sam60000Null
4Max90000Null

Output:

Employee
Joe

解释: 乔是唯一一个收入比经理高的员工。

解决方案

SELECT e1.name AS Employee
FROM employee e1
JOIN employee e2
    ON e1.Managerid = e2.id
WHERE e1.salary > e2.salary;

21. 从来没有下过订单的顾客

Table: Customers

Column NameType
idint
namevarchar

id 是该表的主键(具有唯一值的列)。该表的每一行都表示一位客户的 ID 和姓名。

Table: Orders

Column NameType
idint
customerIdint

id 是该表的主键(具有唯一值的列)。customerId 是客户表 ID 的外键(引用列)。该表的每一行都表示订单的 ID 和订购该订单的客户的 ID。

编写一个解决方案,找出所有从未订购过任何东西的客户。按任意顺序返回结果表。结果格式如下例所示。

Example 1:

Input:
Customers table:

idname
1Joe
2Henry
3Sam
4Max

Orders table:

idcustomerId
13
21

Output:

Customers
Henry
Max

解决方案

SELECT c.name AS customers
FROM customers c
LEFT JOIN orders o
    ON c.id = o.customerid
WHERE o.id IS NULL;

22. 部门最高薪水

Table: Employee

Column NameType
idint
namevarchar
salaryint
departmentIdint

id 是该表的主键(具有唯一值的列)。departmentId 是部门表中 ID 的外键(引用列)。该表的每一行都显示了员工的 ID、姓名和工资。它还包含其部门的 ID。

Table: Department

Column NameType
idint
namevarchar

id 是该表的主键(具有唯一值的列)。保证部门名称不是空值。该表的每一行都表示一个部门的 ID 及其名称。

编写一个解决方案,找出每个部门中工资最高的员工。按任意顺序返回结果表。结果格式如下例所示。

Example 1:
Input:
Employee table:

idnamesalarydepartmentId
1Joe700001
2Jim900001
3Henry800002
4Sam600002
5Max900001

Department table:

idname
1IT
2Sales

Output:

DepartmentEmployeeSalary
ITJim90000
SalesHenry80000
ITMax90000

解释:麦克斯和吉姆都是信息技术部门工资最高的人,而亨利是销售部门工资最高的人。

解决方案

WITH max_salary AS (
    SELECT departmentid, max(salary) AS max_salary
    FROM employee
    GROUP BY departmentid
)

SELECT d.name department, e.name employee, e.salary
FROM max_salary ms
JOIN employee e
    ON ms.departmentid = e.departmentid AND ms.max_salary = e.salary
JOIN department d
  ON e.departmentid = d.id;

23. 气温比前一天高

Table: Weather

Column NameType
idint
recordDatedate
temperatureint

id 是该表具有唯一值的列。没有记录日期相同的不同行。该表包含某天的温度信息。

编写一个解决方案,找出与前一天(昨天)相比温度较高的所有日期的 Id。以任意顺序返回结果表。结果格式见下例。

Example 1:

Input:
Weather table:

idrecordDatetemperature
12015-01-0110
22015-01-0225
32015-01-0320
42015-01-0430

Output:

id
2
4

Explanation:
2015-01-02,气温高于前一天(10 -> 25)。
2015-01-04,气温高于前一天(20 -> 30)。

解决方案

SELECT w2.id
FROM weather w1
JOIN weather w2
    ON DATEADD(day,1,w1.recorddate) = w2.recorddate
WHERE w1.temperature < w2.temperature;

24. 行程和用户

Table: Trips

Column NameType
idint
client_idint
driver_idint
city_idint
statusenum
request_atdate

id 是该表的主键(具有唯一值的列)。该表保存所有出租车行程。每个行程都有一个唯一的 id,而客户_id 和司机_id 是用户表中 users_id 的外键。状态是一个 ENUM(类别)类型 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’).

Table: Users

Column NameType
users_idint
bannedenum
roleenum

users_id 是该表的主键(具有唯一值的列)。该表包含所有用户。每个用户都有唯一的 users_id,角色是 ENUM 类型(“客户”、“司机”、“合作伙伴”)。禁止是一个 ENUM(类别)类型(“是”、“否”)。

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

请写出一个解决方案,求出 "2013-10-01 "至 "2013-10-03 "期间每天未被禁用用户(客户端和驱动程序都必须未被禁用)的请求取消率。将取消率四舍五入到小数点后两位。按任意顺序返回结果表。

结果格式如下。

Example 1:

Input:
Trips table:

idclient_iddriver_idcity_idstatusrequest_at
11101completed2013-10-01
22111cancelled_by_driver2013-10-01
33126completed2013-10-01
44136cancelled_by_client2013-10-01
51101completed2013-10-02
62116completed2013-10-02
73126completed2013-10-02
821212completed2013-10-03
931012completed2013-10-03
1041312cancelled_by_driver2013-10-03

Users table:

users_idbannedrole
1Noclient
2Yesclient
3Noclient
4Noclient
10Nodriver
11Nodriver
12Nodriver
13Nodriver

Output:

DayCancellation Rate
2013-10-010.33
2013-10-020.00
2013-10-030.50

Explanation:
2013-10-01:

  • 共有 4 个请求,其中 2 个被取消。
  • 但是,Id=2 的请求是由一个被禁用的客户端(User_Id=2)提出的,因此在计算中被忽略。
  • 因此,共有 3 个未被禁用的请求,其中 1 个被取消。
  • 取消率为 (1 / 3) = 0.33
    在 2013-10-02:
  • 共有 3 个请求,其中 0 个被取消。
  • Id=6 的请求是由一个被禁用的客户端提出的,因此被忽略。
  • 因此,共有 2 个未被禁用的请求,其中 0 个被取消。
  • 取消率为 (0 / 2) = 0.00
    2013-10-03:
  • 共有 3 个请求,其中 1 个被取消。
  • Id=8 的请求是由被禁用的客户端提出的,因此被忽略。
  • 因此,共有 2 个未被禁用的请求,其中 1 个被取消。
  • 取消率为 (1 / 2) = 0.50

解决方案

SELECT t.Request_at AS 'Day', 
    CAST(
        AVG(CASE 
                WHEN status = 'completed' then 0
                ELSE 1.0
            END)
        AS DECIMAL(3,2)
    ) AS 'Cancellation Rate'
FROM Trips AS t
INNER JOIN Users c 
    ON t.Client_Id=c.Users_Id
INNER JOIN Users d 
    ON t.Driver_Id=d.Users_Id
-- filter our banned client and driver and limit time frame
WHERE c.Banned='no' AND
      d.Banned='no' AND
      t.Request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY t.Request_at;

25. 游戏数据分析

Table: Activity

Column NameType
player_idint
device_idint
event_datedate
games_playedint

(player_idevent_date)是该表的主键。
该表显示了某款游戏的玩家活动。
每一行都是一个玩家的记录,该玩家在某天使用某个设备登录并玩了若干游戏(可能为 0),然后注销。

编写一个 SQL 查询,报告每个玩家首次登录的设备。

查询结果格式如下:

Activity table:

player_iddevice_idevent_dategames_played
122016-03-015
122016-05-026
232017-06-251
312016-03-020
342018-07-035

Result table:

player_iddevice_id
12
23
31

解决方案

SELECT a.player_id, device_id
FROM Activity a
JOIN (
    SELECT player_id, MIN(event_date) min_date
    FROM Activity
    GROUP BY player_id
    ) tb1
ON a.player_id = tb1.player_id AND a.event_date = tb1.min_date;

26. 游戏数据分析

Table: Activity

Column NameType
player_idint
device_idint
event_datedate
games_playedint

(player_id,event_date)是该表的主键(具有唯一值的列组合)。此表显示某些游戏的玩家活动。
每一行都是一个玩家的记录,该玩家登录并玩了若干游戏(可能为 0),然后在某天使用某种设备注销。

请写一个解决方案,以报告在首次登录后的第二天再次登录的玩家比例,四舍五入到小数点后 2 位。换句话说,您需要计算从首次登录日期开始至少连续两天登录的玩家人数,然后用该人数除以玩家总数。

结果格式如下。

Example 1:

Input:
Activity table:

player_iddevice_idevent_dategames_played
122016-03-015
122016-03-026
232017-06-251
312016-03-020
342018-07-035

Output:

fraction
0.33

Explanation:
只有id为1的玩家在登录第一天后重新登录,因此答案为 1/3 = 0.33

解决方案

SELECT CAST(
    -- using DISTINCT to avoid double counting
    COUNT(DISTINCT a2.player_id)*1.0/COUNT(DISTINCT a1.player_id)
    AS DECIMAL(3,2)
) AS fraction
FROM (
    -- get the first-logged-in date of each player
    SELECT player_id, MIN(event_date) AS event_date
    FROM Activity
    GROUP BY player_id
) a1
-- if a player logged back in on the day right after the first-logged-in date, 
-- he/she would get a matched record from table a2
LEFT JOIN Activity a2
ON a1.player_id = a2.player_id AND DATEADD(day,1,a1.event_date) = a2.event_date;

27. 拥有至少 5 名直接下属的经理

Table: Employee

Column NameType
idint
namevarchar
departmentvarchar
managerIdint

id 是该表的主键(具有唯一值的列)。
该表的每一行都显示了员工姓名、部门及其经理的 id。
如果 managerId 为空,则表示该员工没有经理。
没有员工会成为自己的经理。

编写一个解决方案,查找至少有五名直接下属的经理。
以任意顺序返回结果表。

结果格式如下。

Example 1:

Input:
Employee table:

idnamedepartmentmanagerId
101JohnAnull
102DanA101
103JamesA101
104AmyA101
105AnneA101
106RonB101

Output:

name
John

解决方案

SELECT e2.name
FROM employee e1
JOIN employee e2
ON e1.managerid = e2.id
GROUP BY e2.id, e2.name
HAVING COUNT(e1.id) >= 5;

28. 赢家候选

Table: Candidate

idName
1A
2B
3C
4D
5E

Table: Vote

idCandidateId
12
24
33
42
55

id 是自动递增主键、
CandidateId 是候选人表中出现的 id。

编写一个 sql 查找获胜候选人的姓名,上面的示例将返回获胜者 B。

Name
B

Notes:

你可以假设没有平局,换句话说,最多会有一个获胜的候选人。

解决方案

SELECT TOP 1 c.Name
FROM Candidate c
JOIN Vote v
ON c.id = v.CandidateId
GROUP BY c.id, c.Name
ORDER BY COUNT(*) DESC;

29.

Table: Employee

Column NameType
empIdint
namevarchar
supervisorint
salaryint

empId 是该表唯一值列。
该表的每一行都显示了雇员的姓名和 ID,以及他们的工资和经理 ID。

Table: Bonus

Column NameType
empIdint
bonusint

empId 是该表的唯一值列。
empId 是雇员表中 empId 的外键(引用列)。
该表的每一行都包含一名雇员的 id 和他们各自的奖金。

编写一个解决方案,报告奖金少于 1000 的每位员工的姓名和奖金数额。

以任意顺序返回结果表。

结果格式如下例所示。

Example 1:

Input:
Employee table:

empIdnamesupervisorsalary
3Bradnull4000
1John31000
2Dan32000
4Thomas34000

Bonus table:

empIdbonus
2500
42000

Output:

namebonus
Bradnull
Johnnull
Dan500

解决方案

SELECT e.name, b.bonus
FROM Employee e
LEFT JOIN Bonus b
ON e.empId = b.empId
-- when employee has no bonus, his/her bonus will be null after left join
WHERE b.bonus IS NULL 
    OR b.bonus < 1000;

30. 统计各系学生人数

某大学使用两个数据表(学生表和院系表)来存储有关学生和各专业相关院系的数据。

编写一个查询,打印系表中所有系(即使是没有在校学生的系)各自的系名和每个系的学生人数。

按学生人数从多到少排序;如果两个或多个系的学生人数相同,则按系名的字母顺序排序。

学生表如下:

Column NameType
student_idInteger
student_nameString
genderCharacter
dept_idInteger

其中 student_id 是学生的 ID 编号,student_name 是学生的姓名,gender 是学生的性别,dept_id 是与学生申报专业相关的系 ID。

系表描述如下:

Column NameType
dept_idInteger
dept_nameString

其中,dept_id 是部门的 ID 编号,dept_name 是部门名称。

下面是一个输入示例:
学生表:

student_idstudent_namegenderdept_id
1JackM1
2JaneF1
3MarkM2

department table:

dept_iddept_name
1Engineering
2Science
3Law

The Output should be:

dept_namestudent_number
Engineering2
Science1
Law0

解决方案

SELECT d.dept_name, COUNT(student_id) AS student_number
FROM department d
LEFT JOIN student s
ON d.dept_id = s.dept_id
GROUP BY d.dept_id, d.dept_name
ORDER BY student_number DESC, d.dept_name;

31. 销售人员

Table: SalesPerson

Column NameType
sales_idint
namevarchar
salaryint
commission_rateint
hire_datedate

sales_id 是该表的主键(具有唯一值的列)。
该表的每一行都显示销售人员的姓名和 ID,以及他们的工资、佣金率和雇用日期。

Table: Company

Column NameType
com_idint
namevarchar
cityvarchar

com_id 是该表的主键(具有唯一值的列)。
该表中的每一行都表示一家公司的名称和 ID 以及该公司所在的城市。

Table: Orders

Column NameType
order_idint
order_datedate
com_idint
sales_idint
amountint

order_id 是该表的主键(具有唯一值的列)。
com_id 是公司表中 com_id 的外键(引用列)。
sales_id 是销售人员表中 sales_id 的外键(引用列)。
该表的每一行都包含一个订单的信息。其中包括公司 ID、销售人员 ID、订单日期和支付金额。

编写一个解决方案,找出与名称为 "RED "的公司没有任何订单的所有销售人员的姓名。

按任意顺序返回结果表。

结果格式见下例。

Example 1:

Input:

SalesPerson table:

sales_idnamesalarycommission_ratehire_date
1John10000064/1/2006
2Amy1200055/1/2010
3Mark650001212/25/2008
4Pam25000251/1/2005
5Alex5000102/3/2007

Company table:

com_idnamecity
1REDBoston
2ORANGENew York
3YELLOWBoston
4GREENAustin

Orders table:

order_idorder_datecom_idsales_idamount
11/1/20143410000
22/1/2014455000
33/1/20141150000
44/1/20141425000

Output:

name
Amy
Mark
Alex

解决方案

SELECT name
FROM salesperson
WHERE sales_id NOT IN (
    SELECT o.sales_id
    FROM orders o
    JOIN company c
    ON o.com_id = c.com_id
    WHERE c.name = 'RED'
);

32. 二级追随者

Table: Follow

Column NameType
followeevarchar
followervarchar

(followee,follower)是该表的主键(具有唯一值的列组合)。
该表中的每一行都表示用户关注者在社交网络上关注了用户被关注者。
不会出现用户关注自己的情况。

二级关注者是指具备以下条件的用户

  1. 至少关注一个用户,且
  2. 被至少一个用户关注。

编写一个解决方案,报告二级用户及其关注者的数量。

按关注者的字母顺序返回结果表。

结果格式如下。

Example 1:

Input:
Follow table:

followeefollower
AliceBob
BobCena
BobDonald
DonaldEdward

Output:

followernum
Bob2
Donald1

Explanation:
用户 Bob 有 2 个关注者。鲍勃是二级关注者,因为他关注了爱丽丝,所以我们把他包括在结果表中。
用户 Donald 有 1 个关注者。唐纳德是二级关注者,因为他关注了鲍勃,所以我们将他包含在结果表中。
用户 Alice 有 1 个关注者。爱丽丝不是二级关注者,因为她没有关注任何人,所以我们没有将她包括在结果表中。

解决方案

SELECT f1.follower, COUNT(DISTINCT f2.follower) AS num
FROM follow f1
JOIN follow f2
ON f1.follower = f2.followee
GROUP BY f1.follower
ORDER BY f1.follower;

33. 平均工资:部门 VS 公司

给定以下两个表格,编写一个查询,以显示部门员工平均工资与公司平均工资的比较结果(较高/较低/相同)。

Table: salary

idemployee_idamountpay_date
1190002017-03-31
2260002017-03-31
33100002017-03-31
4170002017-02-28
5260002017-02-28
6380002017-02-28

employee_id 列指的是下表 employee 中的 employee_id。

employee_iddepartment_id
11
22
32

因此,上述样本数据的结果是

pay_monthdepartment_idcomparison
2017-031higher
2017-032lower
2017-021same
2017-022same

Explanation:

三月份,公司的平均工资为 (9000+6000+10000)/3 = 8333.33…

部门’1’的平均工资是 9000,也就是员工编号’1’的工资,因为该部门只有一名员工。因此,比较结果是 “更高”,因为 9000 显然大于 8333.33。

部门’2’的平均工资为 (6000 + 10000)/2 = 8000,这是员工编号’2’和’3’的平均工资。因此,比较结果是 “较低”,因为 8000 < 8333.33。

用同样的公式比较二月份的平均工资,结果是 “相同”,因为部门 "1 "和 "2 "与公司的平均工资相同,都是 7000。

解决方案

-- If need to extract date in other format in the future, FORMAT() function could be used

-- Solution 1: Join, Window Function, Subquery, CASE WHEN
WITH tb1 AS (
    SELECT DISTINCT department_id, LEFT(pay_date,7) AS pay_month,
        AVG(amount) OVER (PARTITION BY department_id, LEFT(pay_date,7))AS avg_dept,
        AVG(amount) OVER (PARTITION BY LEFT(pay_date,7)) AS avg_comp
    FROM salary s
    JOIN employee e
    ON s.employee_id = e.employee_id
)

SELECT pay_month, department_id,
    CASE
        WHEN avg_dept > avg_comp THEN 'higher'
        WHEN avg_dept < avg_comp THEN 'lower'
        ELSE 'same'
    END AS comparison
FROM tb1;



-- Solution 2: Join, Subquery, CASE WHEN
WITH dept AS (
    SELECT e.department_id, LEFT(s.pay_date,7) AS pay_month, AVG(s.amount) AS avg_dept
    FROM salary s
    JOIN employee e
    ON s.employee_id = e.employee_id
    GROUP BY e.department_id, LEFT(s.pay_date,7)
),
comp AS (
    SELECT LEFT(pay_date,7) AS pay_month, AVG(amount) AS avg_comp
    FROM salary
    GROUP BY LEFT(pay_date,7)
)

SELECT d.department_id, d.pay_month,
    CASE
        WHEN d.avg_dept > c.avg_comp THEN 'higher'
        WHEN d.avg_dept < c.avg_comp THEN 'lower'
        ELSE 'same'
    END AS comparison
FROM dept d
JOIN comp c
ON d.pay_month = c.pay_month;

34.

35.

36.

37.

38.

39.

40.

41.

42.

43.

44.

45.

46.

47.

48.

49.

50.

51.

52.

53.

54.

55.

56.

57.

58.

59.

60.

61.

62.

63.

64.

65.

66.

67.

68.

69.

70.

71.

72.

73.

74.

75.

76.

77.

78.

79.

80.

81.

82.

83.

84.

85.

86.

87.

88.

89.

90.

91.

92.

93.

94.

95.

96.

97.

98.

99.

100.

101.

102.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值