LeetCode Record
xcbyao 小妖

Pref

LeetCode 刷题记录。 Hard

Convert the Temperature - Easy

Kelvin = Celsius + 273.15
Fahrenheit = Celsius * 1.80 + 32.00

1
2
3
class Solution:
def convertTemperature(self, celsius: float) -> List[float]:
return [celsius + 273.15, celsius * 1.80 + 32.00]

Smallest Even Multiple - Easy

最小偶倍数:

Given a positive integer n, return the smallest positive integer that is a multiple of both 2 and n.

1
2
3
4
5
6
7
8
9
class Solution:
def smallestEvenMultiple(self, n: int) -> int:
return n if n % 2 == 0 else n * 2
# return n << (n & 1)
'''
位运算避免分支判断。常用 n & 1 判断奇数,二进制奇数最低位一定为 1,
因此,若按位与结果为 1,则最后一位为 1,n 为奇数;若为 0,则为偶数。
'''
# return (n % 2) == 0 ? n : n * 2

XOR Operation in an Array - Easy

给你两个整数,n 和 start。

定义 nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length。

请返回 nums 中所有元素按位异或后得到的结果。

输入:n = 5, start = 0
输出:8
解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。

1
2
3
4
5
6
7
# 模拟
class Solution:
def xorOperation(self, n: int, start: int) -> int:
ans = 0
for i in range(n):
ans ^= (start + i * 2)
return ans

方法二:数学

Number of Good Pairs - Easy

好数对的数目:

给你一个整数数组 nums。

如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组好数对。

返回好数对的数目。

输入:nums = [1,2,3,1,1,3]
输出:4
解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始

1
2
3
4
5
6
7
8
9
# 暴力统计
class Solution:
def numIdenticalPairs(self, nums: List[int]) -> int:
ans = 0
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] == nums[j]:
ans += 1
return ans

方法二:组合计数

Count Good Triplets - Easy

一个整数数组 arr,以及 a、b 、c 三个整数。

如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件,则认为它是一个好三元组。

0 <= i < j < k < arr.length
|arr[i] - arr[j]| <= a
|arr[j] - arr[k]| <= b
|arr[i] - arr[k]| <= c
其中 |x| 表示 x 的绝对值。

返回好三元组的数量。

输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
输出:4
解释:一共 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 枚举
class Solution:
def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
n = len(arr)
cnt = 0
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
if abs(arr[i] - arr[j]) <= a and abs(arr[j] - arr[k]) <= b and abs(arr[i] - arr[k]) <= c:
cnt += 1
return cnt

# 暴力法三重循环可以提前判断终止最内层的计算
class Solution:
def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
size = len(arr)
cnt = 0
for i in range(size-2):
for j in range(i+1,size-1):
if abs(arr[i] - arr[j]) <= a:
for k in range(j+1, size):
if abs(arr[j] - arr[k]) <= b and abs(arr[i] - arr[k]) <= c:
cnt += 1
return cnt

方法二:枚举优化

Add Digits - Easy

各位相加:

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

输入: num = 38
输出: 2
解释: 各位相加的过程为:
38 –> 3 + 8 –> 11
11 –> 1 + 1 –> 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 模拟
class Solution:
def addDigits(self, num: int) -> int:
while num >= 10:
sum = 0
while num:
sum += num % 10
num //= 10
num = sum
return num

# 数学
class Solution:
def addDigits(self, num: int) -> int:
return (num - 1) % 9 + 1 if num else 0

方法二:数学

Subtract the Product and Sum of Digits of an Integer - Easy

整数的各位积和之差:

整数 n,计算并返回该整数「各位数字之积」与「各位数字之和」的差。

输入:n = 234
输出:15
解释:
各位数之积 = 2 * 3 * 4 = 24
各位数之和 = 2 + 3 + 4 = 9
结果 = 24 - 9 = 15

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 模拟
class Solution:
def subtractProductAndSum(self, n: int) -> int:
add, mul = 0, 1
while n > 0:
add += n % 10
mul *= n % 10
n //= 10
return mul - add

# 暴力
class Solution:
def subtractProductAndSum(self, n: int) -> int:
add, mul = 0, 1
for num in str(n):
num = int(num)
add += num
mul *= num
return mul - add

Power of Two - Easy

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true;否则返回 false。

输入:n = 1
输出:true
解释:2^0 = 1

1
2
3
4
5
6
# 判断是否为最大 2 的幂的约数
class Solution:
BIG = 2**30

def isPowerOfTwo(self, n: int) -> bool:
return n > 0 and Solution.BIG % n == 0

方法一:二进制表示

Power of Three - Easy

1
2
3
4
5
6
7
8
9
10
11
12
# 试除法
class Solution:
def isPowerOfThree(self, n: int) -> bool:
while n and n % 3 == 0:
n //= 3
return n == 1

# 判断是否为最大 3 的幂的约数
# 这里限定范围最大 3 的幂为 3^19 = 1162261467
class Solution:
def isPowerOfThree(self, n: int) -> bool:
return n > 0 and 1162261467 % n == 0

Ugly Number - Easy

丑数:只包含质因数 2、3 和 5 的正整数。

1 没有质因数,因此它的全部质因数是 {2, 3, 5} 的空集。习惯上将其视作第一个丑数。

给你一个整数 n,请你判断 n 是否为丑数。如果是,返回 true;否则返回 false。

输入:n = 6
输出:true
解释:6 = 2 × 3

1
2
3
4
5
6
7
8
9
10
11
12
# 数学
class Solution:
def isUgly(self, n: int) -> bool:
if n <= 0:
return False

factors = [2, 3, 5]
for factor in factors:
while n % factor == 0:
n //= factor

return n == 1

Shuffle the Array - Easy

重新排序数组:

给你一个数组 nums,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。

请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 一次遍历
class Solution:
def shuffle(self, nums: List[int], n: int) -> List[int]:
ans = [0] * (2 * n)
for i in range(n):
ans[2 * i] = nums[i]
ans[2 * i + 1] = nums[n + i]
return ans

# 切片赋值
class Solution:
def shuffle(self, nums: List[int], n: int) -> List[int]:
nums[::2], nums[1::2] = nums[:n], nums[n:]
return nums

# 模拟
class Solution:
def shuffle(self, nums: List[int], n: int) -> List[int]:
ans = []
for i in range(n):
ans.append(nums[i])
ans.append(nums[n + i])
return ans

Transpose Matrix - Easy

二维整数数组 matrix,返回 matrix 的转置矩阵。

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[1,4,7],[2,5,8],[3,6,9]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 模拟
class Solution:
def transpose(self, matrix: List[List[int]]) -> List[List[int]]:
m, n = len(matrix), len(matrix[0])
transposed = [[0] * m for _ in range(n)]
for i in range(m):
for j in range(n):
transposed[j][i] = matrix[i][j]
return transposed

# 模拟 python3_oneline
class Solution:
def transpose(self, matrix: List[List[int]]) -> List[List[int]]:
return list(list(row) for row in zip(*matrix))
# return [list(row) for row in zip(*matrix)] # 强制转换返回列表值

# 迭代器
class Solution:
def transpose(self, matrix: List[List[int]]):
return zip(*matrix)

# numpy 库
class Solution:
def transpose(self, matrix: List[List[int]]) -> List[List[int]]:
import numpy as np
return np.array(matrix).T.tolist()

Maximum Score After Splitting a String - Easy

分割字符串的最大得分:

由若干 0 和 1 组成的字符串 s,计算并返回将该字符串分割成两个非空子字符串(即左和右子字符串)所能获得的最大得分。

「分割字符串的得分」为左子字符串中 0 的数量加上右子字符串中 1 的数量。

输入:s = “011101”
输出:5
解释:
将字符串 s 划分为两个非空子字符串的可行方案有:
左子字符串 = “0” 且 右子字符串 = “11101”,得分 = 1 + 4 = 5
左子字符串 = “01” 且 右子字符串 = “1101”,得分 = 1 + 3 = 4
左子字符串 = “011” 且 右子字符串 = “101”,得分 = 1 + 2 = 3
左子字符串 = “0111” 且 右子字符串 = “01”,得分 = 1 + 1 = 2
左子字符串 = “01110” 且 右子字符串 = “1”,得分 = 2 + 1 = 3

1
2
3
4
5
6
7
8
9
10
11
12
13
# 枚举每个分割点
class Solution:
def maxScore(self, s: str) -> int:
return max(s[:i].count('0') + s[i:].count('1') for i in range(1, len(s)))

# 两次遍历
class Solution:
def maxScore(self, s: str) -> int:
ans = score = (s[0] == '0') + s[1:].count('1')
for c in s[1:-1]:
score += 1 if c == '0' else -1
ans = max(ans, score)
return ans

Count the Number of Vowel Strings in Range - Easy

统计范围内的元音字符串数:

给你一个下标从 0 开始的字符串数组 words 和两个整数:left 和 right。

如果字符串以元音字母开头并以元音字母结尾,那么该字符串就是一个元音字符串,其中元音字母是 ‘a’、’e’、’i’、’o’、’u’。

返回 words[i] 是元音字符串的数目,其中 i 在闭区间 [left, right] 内。

输入:words = [“are”,”amy”,”u”], left = 0, right = 2
输出:2
解释:

  • “are” 是一个元音字符串,因为它以 ‘a’ 开头并以 ‘e’ 结尾。
  • “amy” 不是元音字符串,因为它没有以元音字母结尾。
  • “u” 是一个元音字符串,因为它以 ‘u’ 开头并以 ‘u’ 结尾。
    在上述范围中的元音字符串数目为 2 。
1
2
3
class Solution:
def vowelStrings(self, words: List[str], left: int, right: int) -> int:
return sum(s[0] in "aeiou" and s[-1] in "aeiou" for s in words[left:right+1])

Peak Index in a Mountain Array - Medium

山脉数组的峰顶索引:

符合下列属性的数组 arr 称为 山脉数组:
arr.length >= 3
存在 i(0 < i < arr.length - 1)使得:
arr[0] < arr[1] < … arr[i-1] < arr[i]
arr[i] > arr[i+1] > … > arr[arr.length - 1]

给你由整数组成的山脉数组 arr,返回满足 arr[0] < arr[1] < … arr[i - 1] < arr[i] > arr[i + 1] > … > arr[arr.length - 1] 的下标 i。

设计并实现时间复杂度为 O(logn) 的解决方案。

输入:arr = [0,2,1,0]
输出:1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 枚举,时间复杂度 O(n)
class Solution:
def peakIndexInMountainArray(self, arr: List[int]) -> int:
ans = -1

for i in range(1, len(arr)-1):
if arr[i] > arr[i+1]:
ans = i
break
return ans

# 二分查找
class Solution:
def peakIndexInMountainArray(self, arr: List[int]) -> int:
left, right, ans = 1, len(arr) - 2, 0

while left <= right:
mid = (left + right) // 2
if arr[mid] > arr[mid + 1]:
ans = mid
right = mid - 1
else:
left = mid + 1
return ans

Database

Find Customer Referee - Easy

寻找用户推荐人:

1
2
3
4
5
6
7
8
9
10
11
Table: Customer
+----+------+------------+
| id | name | referee_id |
+----+------+------------+
| 1 | Will | null |
| 2 | Jane | null |
| 3 | Alex | 2 |
| 4 | Bill | null |
| 5 | Zack | 1 |
| 6 | Mark | 2 |
+----+------+------------+

写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都不是 2。

1
2
3
4
5
6
7
8
9
Output:
+------+
| name |
+------+
| Will |
| Jane |
| Bill |
| Zack |
+------+

MySQL 使用三值逻辑 —— TRUE, FALSE 和 UNKNOWN。任何与 NULL 值进行的比较都会与第三种值 UNKNOWN 做比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT name FROM customer WHERE referee_id <> 2 OR referee_id IS NULL;

-- MySQL
SELECT name FROM customer WHERE referee_id != 2 OR referee_id IS NULL;

-- 用安全等于取反
SELECT name FROM customer WHERE NOT referee_id <=> 2;
/*
因此,最后一句意思是选择所有 referee_id 不等于 2 的行,包括 NULL 行。
<=> 是 MySQL 特有的运算符,用于比较两个值是否相等,包括 NULL 值。使用方式:

如果两个值都不是 NULL,"<=>" 的作用与 "=" 相同,即比较两个值是否相等。
如果其中一个值为 NULL,那么 "<=>" 的结果为 FALSE(不相等),而"=" 的结果为 UNKNOWN(未知)。
如果两个值都为 NULL,那么 "<=>" 的结果为 TRUE(相等),而"=" 的结果为 UNKNOWN(未知)。
*/

Recyclable and Low Fat Products - Easy

可回收且低脂的产品:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Table: Products
+-------------+----------+------------+
| product_id | low_fats | recyclable |
+-------------+----------+------------+
| 0 | Y | N |
| 1 | Y | Y |
| 2 | N | Y |
| 3 | Y | Y |
| 4 | N | N |
+-------------+----------+------------+

product_id 是这个表的主键。
low_fats 是枚举类型,取值为以下两种 ('Y', 'N'),其中 'Y' 表示该产品是低脂产品,'N' 则不是。
recyclable 同上。

查找既是低脂又是可回收的产品编号。返回结果无顺序要求。

1
2
3
4
5
6
7
Output:
+-------------+
| product_id |
+-------------+
| 1 |
| 3 |
+-------------+
1
2
3
-- MySQL
SELECT product_id FROM products WHERE low_fats = 'Y' AND recyclable = 'Y'
;

Big Countries - Easy

1
2
3
4
5
6
7
8
9
10
11
Table: World
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| name | varchar |
| continent | varchar |
| area | int |
| population | int |
| gdp | bigint |
+-------------+---------+
name is the primary key column

面积至少为 300 万平方公里,或人口至少为 2500 万。
编写一个 SQL 查询以报告大国的国家名称、人口和面积。

按任意顺序返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
World table:
+-------------+-----------+---------+------------+--------------+
| name | continent | area | population | gdp |
+-------------+-----------+---------+------------+--------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000000 |
| Albania | Europe | 28748 | 2831741 | 12960000000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000000 |
| Andorra | Europe | 468 | 78115 | 3712000000 |
| Angola | Africa | 1246700 | 20609294 | 100990000000 |
+-------------+-----------+---------+------------+--------------+
Output:
+-------------+------------+---------+
| name | population | area |
+-------------+------------+---------+
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
+-------------+------------+---------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- MySQL
-- 使用 OR
SELECT name, population, area
FROM world
WHERE population >= 25000000 OR area >= 3000000
;

-- 使用 or 可能会使索引失效,在数据量较大的时候查找效率较低,通常建议使用 union。
-- 使用 UNION,比上一种速度更块,但差别不大
SELECT name, population, area
FROM world
WHERE population >= 25000000

UNION

SELECT name, population, area
FROM world
WHERE area >= 3000000
;

Article Views I - Easy

文章浏览 I:

1
2
3
4
5
6
7
8
9
10
11
12
Table: Views
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| article_id | int |
| author_id | int |
| viewer_id | int |
| view_date | date |
+---------------+---------+
此表无主键,因此可能会存在重复行。
此表的每一行都表示某人在某天浏览了某位作者的某篇文章。
同一人的 author_id 和 viewer_id 是相同的。

找出所有浏览过自己文章的作者,结果按照 id 升序排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Input:
Views table:
+------------+-----------+-----------+------------+
| article_id | author_id | viewer_id | view_date |
+------------+-----------+-----------+------------+
| 1 | 3 | 5 | 2019-08-01 |
| 1 | 3 | 6 | 2019-08-02 |
| 2 | 7 | 7 | 2019-08-01 |
| 2 | 7 | 6 | 2019-08-02 |
| 4 | 7 | 1 | 2019-07-22 |
| 3 | 4 | 4 | 2019-07-21 |
| 3 | 4 | 4 | 2019-07-21 |
+------------+-----------+-----------+------------+
Output:
+------+
| id |
+------+
| 4 |
| 7 |
+------+
1
2
3
4
5
6
-- MySQL
SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY author_id
;

Invalid Tweets - Easy

1
2
3
4
5
6
7
8
Table: Tweets
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| tweet_id | int |
| content | varchar |
+----------------+---------+
tweet_id is the primary key.

查询所有无效推文的编号(ID)。当推文内容中的字符数严格大于 15 时,该推文是无效的。

以任意顺序返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Input:
Tweets table:
+----------+----------------------------------+
| tweet_id | content |
+----------+----------------------------------+
| 1 | Vote for Biden |
| 2 | Let us make America great again! |
+----------+----------------------------------+
Output:
+----------+
| tweet_id |
+----------+
| 2 |
+----------+
Explanation:
Tweet 1 has length = 14. It is a valid tweet.
Tweet 2 has length = 32. It is an invalid tweet.
1
2
3
4
5
-- MySQL
SELECT tweet_id
FROM tweets
WHERE CHAR_LENGTH(content) > 15
;

Replace Employee ID With The Unique Identifier - Easy

使用唯一标识码替换员工 ID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Table: Employees
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| name | varchar |
+---------------+---------+
id is the primary key.

Table: EmployeeUNI
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| unique_id | int |
+---------------+---------+

展示每位用户的唯一标识码(unique ID );如果某位员工没有唯一标识码,使用 null 填充即可。

你可以以任意顺序返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Input:
Employees table:
+----+----------+
| id | name |
+----+----------+
| 1 | Alice |
| 7 | Bob |
| 11 | Meir |
| 90 | Winston |
| 3 | Jonathan |
+----+----------+
EmployeeUNI table:
+----+-----------+
| id | unique_id |
+----+-----------+
| 3 | 1 |
| 11 | 2 |
| 90 | 3 |
+----+-----------+
Output:
+-----------+----------+
| unique_id | name |
+-----------+----------+
| null | Alice |
| null | Bob |
| 2 | Meir |
| 3 | Winston |
| 1 | Jonathan |
+-----------+----------+
1
2
3
4
5
6
-- MySQL
SELECT unique_id, name
FROM employees
LEFT JOIN employeeUNI
ON employees.id = employeeUNI.id
;

Product Sales Analysis I - Easy

产品销售分析 I:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Table: Sales
+-------------+-------+
| Column Name | Type |
+-------------+-------+
| sale_id | int |
| product_id | int |
| year | int |
| quantity | int |
| price | int |
+-------------+-------+
(sale_id, year) is the primary key of this table.
product_id is a foreign key to Product table.

Table: Product
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
+--------------+---------+
product_id is the primary key of this table.

获取 Sales 表中所有产品对应的产品名称 product_name 以及该产品的所有售卖年份 year 和价格 price。

查询结果中的顺序无特定要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Input:
Sales table:
+---------+------------+------+----------+-------+
| sale_id | product_id | year | quantity | price |
+---------+------------+------+----------+-------+
| 1 | 100 | 2008 | 10 | 5000 |
| 2 | 100 | 2009 | 12 | 5000 |
| 7 | 200 | 2011 | 15 | 9000 |
+---------+------------+------+----------+-------+
Product table:
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 100 | Nokia |
| 200 | Apple |
| 300 | Samsung |
+------------+--------------+
Output:
+--------------+-------+-------+
| product_name | year | price |
+--------------+-------+-------+
| Nokia | 2008 | 5000 |
| Nokia | 2009 | 5000 |
| Apple | 2011 | 9000 |
+--------------+-------+-------+
1
2
3
4
5
6
-- MySQL
SELECT p.product_name, s.year, s.price
FROM sales s
LEFT JOIN product p
ON s.product_id = p.product_id
;

Customer Who Visited but Did Not Make Any Transactions - Easy

进店却未进行过交易的顾客:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Table: Visits
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| visit_id | int |
| customer_id | int |
+-------------+---------+
visit_id is the primary key for this table.

Table: Transactions
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| transaction_id | int |
| visit_id | int |
| amount | int |
+----------------+---------+
transaction_id is the primary key for this table.

有一些顾客可能光顾了购物中心但没有进行交易。请你编写一个 SQL 查询,来查找这些顾客的 ID,以及他们只光顾不交易的次数。

返回以 任何顺序 排序的结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Input:
Visits
+----------+-------------+
| visit_id | customer_id |
+----------+-------------+
| 1 | 23 |
| 2 | 9 |
| 4 | 30 |
| 5 | 54 |
| 6 | 96 |
| 7 | 54 |
| 8 | 54 |
+----------+-------------+
Transactions
+----------------+----------+--------+
| transaction_id | visit_id | amount |
+----------------+----------+--------+
| 2 | 5 | 310 |
| 3 | 5 | 300 |
| 9 | 5 | 200 |
| 12 | 1 | 910 |
| 13 | 2 | 970 |
+----------------+----------+--------+
Output:
+-------------+----------------+
| customer_id | count_no_trans |
+-------------+----------------+
| 54 | 2 |
| 30 | 1 |
| 96 | 1 |
+-------------+----------------+
解释:
ID = 23 的顾客曾经逛过一次购物中心,并在 ID = 12 的访问期间进行了一笔交易。
ID = 9 的顾客曾经逛过一次购物中心,并在 ID = 13 的访问期间进行了一笔交易。
ID = 30 的顾客曾经去过购物中心,并且没有进行任何交易。
ID = 54 的顾客三度造访了购物中心。在 2 次访问中,他们没有进行任何交易,在 1 次访问中,他们进行了 3 次交易。
ID = 96 的顾客曾经去过购物中心,并且没有进行任何交易。
如我们所见,ID 为 30 和 96 的顾客一次没有进行任何交易就去了购物中心。顾客 54 也两次访问了购物中心并且没有进行任何交易。
1
2
3
4
5
6
7
8
-- MySQL
SELECT customer_id, count(customer_id) count_no_trans
FROM visits v
LEFT JOIN transactions t
ON v.visit_id = t.visit_id
WHERE amount IS NULL
GROUP BY customer_id
;

Rising Temperature - Easy

1
2
3
4
5
6
7
8
9
Table: Weather
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| recordDate | date |
| temperature | int |
+---------------+---------+
id is the primary key for this table.

查找与之前(昨天的)日期相比温度更高的所有日期的 id。

返回结果不排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Input:
Weather table:
+----+------------+-------------+
| id | recordDate | temperature |
+----+------------+-------------+
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
+----+------------+-------------+
Output:
+----+
| id |
+----+
| 2 |
| 4 |
+----+
解释:
2015-01-02 的温度比前一天高(10 -> 25)
2015-01-04 的温度比前一天高(20 -> 30)
1
2
3
4
5
6
7
8
9
10
11
12
13
-- MySQL
SELECT a.id
FROM weather a
CROSS JOIN weather b
ON datediff(a.recorddate, b.recorddate) = 1
WHERE a.temperature > b.temperature

SELECT a.id
FROM weather a
CROSS JOIN weather b
ON timestampdiff(day, a.recorddate, b.recorddate) = -1
WHERE a.temperature > b.temperature
;

Average Time of Process per Machine - Easy

每台机器的进程平均运行时间:

1
2
3
4
5
6
7
8
9
10
Table: Activity
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| machine_id | int |
| process_id | int |
| activity_type | enum |
| timestamp | float |
+----------------+---------+
(machine_id, process_id, activity_type) 是当前表的主键。

现在有一个工厂网站由几台机器运行,每台机器上运行着相同数量的进程。计算每台机器各自完成一个进程任务的平均耗时。

完成一个进程任务的时间指进程的 ‘end’ 时间戳减去 ‘start’ 时间戳。平均耗时通过计算每台机器上所有进程任务的总耗费时间除以机器上的总进程数量获得。

结果表必须包含 machine_id(机器ID)和对应的 average time(平均耗时) 别名 processing_time,且四舍五入保留 3 位小数。

以 任意顺序 返回表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Input:
Activity table:
+------------+------------+---------------+-----------+
| machine_id | process_id | activity_type | timestamp |
+------------+------------+---------------+-----------+
| 0 | 0 | start | 0.712 |
| 0 | 0 | end | 1.520 |
| 0 | 1 | start | 3.140 |
| 0 | 1 | end | 4.120 |
| 1 | 0 | start | 0.550 |
| 1 | 0 | end | 1.550 |
| 1 | 1 | start | 0.430 |
| 1 | 1 | end | 1.420 |
| 2 | 0 | start | 4.100 |
| 2 | 0 | end | 4.512 |
| 2 | 1 | start | 2.500 |
| 2 | 1 | end | 5.000 |
+------------+------------+---------------+-----------+
Output:
+------------+-----------------+
| machine_id | processing_time |
+------------+-----------------+
| 0 | 0.894 |
| 1 | 0.995 |
| 2 | 1.456 |
+------------+-----------------+
解释:
一共有3台机器,每台机器运行着两个进程.
机器 0 的平均耗时: ((1.520 - 0.712) + (4.120 - 3.140)) / 2 = 0.894
1
2
3
4
5
6
-- MySQL
SELECT
machine_id,
ROUND(AVG(IF(activity_type = 'start', -timestamp, timestamp)) * 2, 3) processing_time
FROM activity
GROUP BY machine_id

Employee Bonus - Easy

选出所有 bonus < 1000 员工的 name 及其 bonus。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Input:
Employee table:
+-------+--------+------------+--------+
| empId | name | supervisor | salary |
+-------+--------+------------+--------+
| 3 | Brad | null | 4000 |
| 1 | John | 3 | 1000 |
| 2 | Dan | 3 | 2000 |
| 4 | Thomas | 3 | 4000 |
+-------+--------+------------+--------+
Bonus table:
+-------+-------+
| empId | bonus |
+-------+-------+
| 2 | 500 |
| 4 | 2000 |
+-------+-------+
Output:
+------+-------+
| name | bonus |
+------+-------+
| Brad | null |
| John | null |
| Dan | 500 |
+------+-------+
1
2
3
4
5
6
7
-- MySQL
SELECT name, bonus
FROM employee
LEFT JOIN bonus
ON employee.empId = bonus.empId
WHERE bonus IS NULL OR bonus < 1000
;

Students and Examinations - Easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Table: Students
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| student_name | varchar |
+---------------+---------+
student_id is the primary key.

Table: Subjects
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| subject_name | varchar |
+--------------+---------+
subject_name is the primary key.

Table: Examinations
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| student_id | int |
| subject_name | varchar |
+--------------+---------+
无主键,可能会有重复行。

查询出每个学生参加每一门科目测试的次数,结果按 student_id 和 subject_name 排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Input:
Students table:
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 1 | Alice |
| 2 | Bob |
| 13 | John |
| 6 | Alex |
+------------+--------------+
Subjects table:
+--------------+
| subject_name |
+--------------+
| Math |
| Physics |
| Programming |
+--------------+
Examinations table:
+------------+--------------+
| student_id | subject_name |
+------------+--------------+
| 1 | Math |
| 1 | Physics |
| 1 | Programming |
| 2 | Programming |
| 1 | Physics |
| 1 | Math |
| 13 | Math |
| 13 | Programming |
| 13 | Physics |
| 2 | Math |
| 1 | Math |
+------------+--------------+
Output:
+------------+--------------+--------------+----------------+
| student_id | student_name | subject_name | attended_exams |
+------------+--------------+--------------+----------------+
| 1 | Alice | Math | 3 |
| 1 | Alice | Physics | 2 |
| 1 | Alice | Programming | 1 |
| 2 | Bob | Math | 1 |
| 2 | Bob | Physics | 0 |
| 2 | Bob | Programming | 1 |
| 6 | Alex | Math | 0 |
| 6 | Alex | Physics | 0 |
| 6 | Alex | Programming | 0 |
| 13 | John | Math | 1 |
| 13 | John | Physics | 1 |
| 13 | John | Programming | 1 |
+------------+--------------+--------------+----------------+
1
2
3
4
5
6
7
8
9
-- MySQL
SELECT a.student_id, a.student_name, b.subject_name, COUNT(e.subject_name) AS attended_exams
FROM Students a
CROSS JOIN Subjects b
LEFT JOIN Examinations e
ON a.student_id = e.student_id
AND b.subject_name = e.subject_name
GROUP BY a.student_id, b.subject_name
ORDER BY a.student_id, b.subject_name

Managers with at Least 5 Direct Reports - Medium

至少有 5 名直接下属的经理:

1
2
3
4
5
6
7
8
9
10
Table: Employee
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
| department | varchar |
| managerId | int |
+-------------+---------+
id is the primary key column.

查询至少有 5 名直接下属的经理。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
Employee table:
+-----+-------+------------+-----------+
| id | name | department | managerId |
+-----+-------+------------+-----------+
| 101 | John | A | None |
| 102 | Dan | A | 101 |
| 103 | James | A | 101 |
| 104 | Amy | A | 101 |
| 105 | Anne | A | 101 |
| 106 | Ron | B | 101 |
+-----+-------+------------+-----------+
Output:
+------+
| name |
+------+
| John |
+------+
1
2
3
4
5
6
7
8
9
-- MySQL
SELECT name
FROM employee AS t1 JOIN(
SELECT managerID
FROM employee
GROUP BY managerID
HAVING COUNT(managerID) >= 5) AS t2
ON t1.id = t2.managerID
;

Confirmation Rate - Medium

确认率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Table: Signups
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| user_id | int |
| time_stamp | datetime |
+----------------+----------+
user_id is the primary key.

Table: Confirmations
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| user_id | int |
| time_stamp | datetime |
| action | ENUM |
+----------------+----------+
(user_id, time_stamp) is the primary key.
user_id is a foreign key.

用户的确认率是 ‘confirmed’ 消息的数量除以请求的确认消息的总数。没有请求任何确认消息的用户的确认率为 0 。确认率四舍五入到小数点后两位。

查找每个用户的确认率。

以任意顺序返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Input:
Signups table:
+---------+---------------------+
| user_id | time_stamp |
+---------+---------------------+
| 3 | 2020-03-21 10:16:13 |
| 7 | 2020-01-04 13:57:59 |
| 2 | 2020-07-29 23:09:44 |
| 6 | 2020-12-09 10:39:37 |
+---------+---------------------+
Confirmations table:
+---------+---------------------+-----------+
| user_id | time_stamp | action |
+---------+---------------------+-----------+
| 3 | 2021-01-06 03:30:46 | timeout |
| 3 | 2021-07-14 14:00:00 | timeout |
| 7 | 2021-06-12 11:57:29 | confirmed |
| 7 | 2021-06-13 12:58:28 | confirmed |
| 7 | 2021-06-14 13:59:27 | confirmed |
| 2 | 2021-01-22 00:00:00 | confirmed |
| 2 | 2021-02-28 23:59:59 | timeout |
+---------+---------------------+-----------+
Output:
+---------+-------------------+
| user_id | confirmation_rate |
+---------+-------------------+
| 6 | 0.00 |
| 3 | 0.00 |
| 7 | 1.00 |
| 2 | 0.50 |
+---------+-------------------+
解释:
用户 6 没有请求任何确认消息。确认率为 0。
用户 3 进行了 2 次请求,都超时了。确认率为 0。
用户 7 提出了 3 个请求,所有请求都得到了确认。确认率为 1。
用户 2 做了 2 个请求,其中一个被确认,另一个超时。确认率为 1 / 2 = 0.5。
1
2
3
4
5
6
7
-- MySQL
SELECT s.user_id, IFNULL(ROUND(SUM(action = 'confirmed') / COUNT(c.action), 2), 0.00) AS confirmation_rate
FROM signups AS s
LEFT JOIN confirmations AS c
ON s.user_id = c.user_id
GROUP BY s.user_id
;

Not Boring Movies - Easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
Cinema table:
+----+------------+-------------+--------+
| id | movie | description | rating |
+----+------------+-------------+--------+
| 1 | War | great 3D | 8.9 |
| 2 | Science | fiction | 8.5 |
| 3 | irish | boring | 6.2 |
| 4 | Ice song | Fantacy | 8.6 |
| 5 | House card | Interesting | 9.1 |
+----+------------+-------------+--------+
Output:
+----+------------+-------------+--------+
| id | movie | description | rating |
+----+------------+-------------+--------+
| 5 | House card | Interesting | 9.1 |
| 1 | War | great 3D | 8.9 |
+----+------------+-------------+--------+

找出所有影片描述为非 boring 的且 id 为奇数的影片,结果请按等级 rating 排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- MySQL
SELECT *
FROM cinema
WHERE MOD(id, 2) = 1
AND description != 'boring'
ORDER BY rating DESC
;

-- SQL
SELECT *
FROM cinema
WHERE id % 2 <> 0
AND description <> 'boring'
ORDER BY rating DESC
;

Average Selling Price - Easy

平均售价:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Table: Prices
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| start_date | date |
| end_date | date |
| price | int |
+---------------+---------+
(product_id, start_date, end_date) is the primary key.

Table: UnitsSold
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| purchase_date | date |
| units | int |
+---------------+---------+
There is no primary key for this table, it may contain duplicates.

查找每种产品的平均售价。average_price 应该四舍五入到小数点后两位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Input:
Prices table:
+------------+------------+------------+--------+
| product_id | start_date | end_date | price |
+------------+------------+------------+--------+
| 1 | 2019-02-17 | 2019-02-28 | 5 |
| 1 | 2019-03-01 | 2019-03-22 | 20 |
| 2 | 2019-02-01 | 2019-02-20 | 15 |
| 2 | 2019-02-21 | 2019-03-31 | 30 |
+------------+------------+------------+--------+
UnitsSold table:
+------------+---------------+-------+
| product_id | purchase_date | units |
+------------+---------------+-------+
| 1 | 2019-02-25 | 100 |
| 1 | 2019-03-01 | 15 |
| 2 | 2019-02-10 | 200 |
| 2 | 2019-03-22 | 30 |
+------------+---------------+-------+
Output:
+------------+---------------+
| product_id | average_price |
+------------+---------------+
| 1 | 6.96 |
| 2 | 16.96 |
+------------+---------------+

平均售价 = 产品总价 / 销售的产品数量。
产品 1 的平均售价 = ((100 * 5)+(15 * 20) )/ 115 = 6.96
产品 2 的平均售价 = ((200 * 15)+(30 * 30) )/ 230 = 16.96
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- MySQL
SELECT
product_id,
Round(SUM(sales) / SUM(units), 2) AS average_price
FROM (
SELECT
Prices.product_id AS product_id,
Prices.price * UnitsSold.units AS sales,
UnitsSold.units AS units
FROM Prices
JOIN UnitsSold ON Prices.product_id = UnitsSold.product_id
WHERE UnitsSold.purchase_date BETWEEN Prices.start_date AND Prices.end_date
) T
GROUP BY product_id

Project Employees I - Easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Table: Project
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| project_id | int |
| employee_id | int |
+-------------+---------+
(project_id, employee_id) is the primary key of this table.
employee_id is a foreign key to Employee table.

Table: Employee
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| employee_id | int |
| name | varchar |
| experience_years | int |
+------------------+---------+
employee_id is the primary key.

查询每一个项目中员工的 平均 工作年限,精确到小数点后两位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Input:
Project table:
+-------------+-------------+
| project_id | employee_id |
+-------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 4 |
+-------------+-------------+
Employee table:
+-------------+--------+------------------+
| employee_id | name | experience_years |
+-------------+--------+------------------+
| 1 | Khaled | 3 |
| 2 | Ali | 2 |
| 3 | John | 1 |
| 4 | Doe | 2 |
+-------------+--------+------------------+
Output:
+-------------+---------------+
| project_id | average_years |
+-------------+---------------+
| 1 | 2.00 |
| 2 | 2.50 |
+-------------+---------------+
第一个项目中,员工的平均工作年限是 (3 + 2 + 1) / 3 = 2.00;第二个项目中,员工的平均工作年限是 (3 + 2) / 2 = 2.50
1
2
3
4
5
6
7
8
-- MySQL
SELECT
p.project_id,
ROUND(AVG(e.experience_years), 2) AS average_years
FROM project p, employee e
WHERE p.employee_id = e.employee_id
GROUP BY p.project_id
;

Percentage of Users Attended a Contest - Easy

各赛事的用户注册率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Table: Users

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| user_id | int |
| user_name | varchar |
+-------------+---------+
user_id is the primary key.

Table: Register

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| contest_id | int |
| user_id | int |
+-------------+---------+
(contest_id, user_id) is the primary key.

查询各赛事的用户注册百分率,保留两位小数。

返回的结果表按 percentage 的 降序 排序,若相同则按 contest_id 的 升序 排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Input:
Users table:
+---------+-----------+
| user_id | user_name |
+---------+-----------+
| 6 | Alice |
| 2 | Bob |
| 7 | Alex |
+---------+-----------+
Register table:
+------------+---------+
| contest_id | user_id |
+------------+---------+
| 215 | 6 |
| 209 | 2 |
| 208 | 2 |
| 210 | 6 |
| 208 | 6 |
| 209 | 7 |
| 209 | 6 |
| 215 | 7 |
| 208 | 7 |
| 210 | 2 |
| 207 | 2 |
| 210 | 7 |
+------------+---------+
Output:
+------------+------------+
| contest_id | percentage |
+------------+------------+
| 208 | 100.0 |
| 209 | 100.0 |
| 210 | 100.0 |
| 215 | 66.67 |
| 207 | 33.33 |
+------------+------------+

解释:
所有用户都注册了 208、209 和 210 赛事,因此这些赛事的注册率为 100% ,我们按 contest_id 的降序排序加入结果表中。
Alice 和 Alex 注册了 215 赛事,注册率为 ((2/3) * 100) = 66.67%
Bob 注册了 207 赛事,注册率为 ((1/3) * 100) = 33.33%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- MySQL
SELECT
contest_id,
ROUND(COUNT(user_id) * 100 / (SELECT count(*) FROM users), 2) percentage
FROM Register
GROUP BY contest_id
ORDER BY percentage desc, contest_id

-- SQL
SELECT
contest_id,
CONVERT(DECIMAL(18, 2), COUNT(user_id * 1.00) * 100 / (SELECT COUNT(*) * 1.00 FROM users)) percentage
FROM Register
GROUP BY contest_id
ORDER BY percentage desc, contest_id

Queries Quality and Percentage - Easy

查询结果的质量和占比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Table: Queries

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| query_name | varchar |
| result | varchar |
| position | int |
| rating | int |
+-------------+---------+

此表没有主键,并可能有重复的行。
此表包含了一些从数据库中收集的查询信息。
“位置”(position)列的值为 1 到 500 。
“评分”(rating)列的值为 1 到 5 。评分小于 3 的查询被定义为质量很差的查询。

将查询结果的质量 quality 定义为:

各查询结果的评分与其位置之间比率的平均值。

将劣质查询百分比 poor_query_percentage 为:

评分小于 3 的查询结果占全部查询结果的百分比。

编写一组 SQL 来查找每次查询的名称(query_name)、质量(quality) 和 劣质查询百分比(poor_query_percentage)。

质量(quality) 和劣质查询百分比(poor_query_percentage) 都应四舍五入到小数点后两位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Input:
Queries table:
+------------+-------------------+----------+--------+
| query_name | result | position | rating |
+------------+-------------------+----------+--------+
| Dog | Golden Retriever | 1 | 5 |
| Dog | German Shepherd | 2 | 5 |
| Dog | Mule | 200 | 1 |
| Cat | Shirazi | 5 | 2 |
| Cat | Siamese | 3 | 3 |
| Cat | Sphynx | 7 | 4 |
+------------+-------------------+----------+--------+
Output:
+------------+---------+-----------------------+
| query_name | quality | poor_query_percentage |
+------------+---------+-----------------------+
| Dog | 2.50 | 33.33 |
| Cat | 0.66 | 33.33 |
+------------+---------+-----------------------+
Dog 查询结果的质量为 ((5 / 1) + (5 / 2) + (1 / 200)) / 3 = 2.50
Dog 查询结果的劣质查询百分比为 (1 / 3) * 100 = 33.33

Cat 查询结果的质量为 ((2 / 5) + (3 / 3) + (4 / 7)) / 3 = 0.66
Cat 查询结果的劣质查询百分比为 (1 / 3) * 100 = 33.33
1
2
3
4
5
6
7
-- MySQL
SELECT
query_name,
ROUND(AVG(rating/position), 2) quality,
ROUND(SUM(IF(rating < 3, 1, 0)) * 100 / COUNT(*), 2) poor_query_percentage
FROM Queries
GROUP BY query_name

Monthly Transactions I - Medium

每月交易 I:

1
2
3
4
5
6
7
8
9
10
11
12
13
Table: Transactions

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| country | varchar |
| state | enum |
| amount | int |
| trans_date | date |
+---------------+---------+
id is the primary key
The state column is an enum of type ["approved", "declined"].

查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
Transactions table:
+------+---------+----------+--------+------------+
| id | country | state | amount | trans_date |
+------+---------+----------+--------+------------+
| 121 | US | approved | 1000 | 2018-12-18 |
| 122 | US | declined | 2000 | 2018-12-19 |
| 123 | US | approved | 2000 | 2019-01-01 |
| 124 | DE | approved | 2000 | 2019-01-07 |
+------+---------+----------+--------+------------+
Output:
+----------+---------+-------------+----------------+--------------------+-----------------------+
| month | country | trans_count | approved_count | trans_total_amount | approved_total_amount |
+----------+---------+-------------+----------------+--------------------+-----------------------+
| 2018-12 | US | 2 | 1 | 3000 | 1000 |
| 2019-01 | US | 1 | 1 | 2000 | 2000 |
| 2019-01 | DE | 1 | 1 | 2000 | 2000 |
+----------+---------+-------------+----------------+--------------------+-----------------------+
1
2
3
4
5
6
7
8
9
10
-- MySQL
SELECT
DATE_FORMAT(trans_date, '%Y-%m') AS month,
country,
COUNT(*) AS trans_count,
COUNT(IF(state = 'approved', 1, NULL)) AS approved_count,
SUM(amount) AS trans_total_amount,
SUM(IF(state = 'approved', amount, 0)) AS approved_total_amount
FROM transactions
GROUP BY month, country

Immediate Food Delivery II - Medium

即时食物配送 II:

1
2
3
4
5
6
7
8
9
10
11
Table: Delivery

+-----------------------------+---------+
| Column Name | Type |
+-----------------------------+---------+
| delivery_id | int |
| customer_id | int |
| order_date | date |
| customer_pref_delivery_date | date |
+-----------------------------+---------+
delivery_id is the primary key

如果顾客期望的配送日期和下单日期相同,则该订单称为 「即时订单」,否则称为「计划订单」。

「首次订单」是顾客最早创建的订单。我们保证一个顾客只会有一个「首次订单」。

写一条 SQL 查询语句获取即时订单在所有用户的首次订单中的比例。保留两位小数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Input:
Delivery table:
+-------------+-------------+------------+-----------------------------+
| delivery_id | customer_id | order_date | customer_pref_delivery_date |
+-------------+-------------+------------+-----------------------------+
| 1 | 1 | 2019-08-01 | 2019-08-02 |
| 2 | 2 | 2019-08-02 | 2019-08-02 |
| 3 | 1 | 2019-08-11 | 2019-08-12 |
| 4 | 3 | 2019-08-24 | 2019-08-24 |
| 5 | 3 | 2019-08-21 | 2019-08-22 |
| 6 | 2 | 2019-08-11 | 2019-08-13 |
| 7 | 4 | 2019-08-09 | 2019-08-09 |
+-------------+-------------+------------+-----------------------------+
Output:
+----------------------+
| immediate_percentage |
+----------------------+
| 50.00 |
+----------------------+

1 号顾客的 1 号订单是首次订单,并且是计划订单。
2 号顾客的 2 号订单是首次订单,并且是即时订单。
3 号顾客的 5 号订单是首次订单,并且是计划订单。
4 号顾客的 7 号订单是首次订单,并且是即时订单。
因此,一半顾客的首次订单是即时的。
1
2
3
4
5
6
7
8
9
10
-- MySQL
SELECT
ROUND(SUM(order_date = customer_pref_delivery_date) * 100 / COUNT(*), 2)
AS immediate_percentage
FROM delivery
WHERE (customer_id, order_date) IN (
SELECT customer_id, min(order_date)
FROM delivery
GROUP BY customer_id
)

Game Play Analysis IV - Medium

游戏玩法分析 IV:

1
2
3
4
5
6
7
8
9
10
11
Table: Activity

+--------------+---------+
| Column Name | Type |
+--------------+---------+
| player_id | int |
| device_id | int |
| event_date | date |
| games_played | int |
+--------------+---------+
(player_id, event_date) is the primary key

编写一个 SQL 查询,报告在首次登录的第二天再次登录的玩家的比率,四舍五入到小数点后两位。换句话说,您需要计算从首次登录日期开始至少连续两天登录的玩家的数量,然后除以玩家总数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
Activity table:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1 | 2 | 2016-03-01 | 5 |
| 1 | 2 | 2016-03-02 | 6 |
| 2 | 3 | 2017-06-25 | 1 |
| 3 | 1 | 2016-03-02 | 0 |
| 3 | 4 | 2018-07-03 | 5 |
+-----------+-----------+------------+--------------+
Output:
+-----------+
| fraction |
+-----------+
| 0.33 |
+-----------+
只有 ID 为 1 的玩家在第一天登录后才重新登录,所以答案是 1/3 = 0.33
1
2
3
4
5
6
7
8
-- MySQL
SELECT ROUND(AVG(a.event_date IS NOT NULL), 2) fraction
FROM
(SELECT player_id, min(event_date) AS login
FROM activity
GROUP BY player_id) p
LEFT JOIN activity a
ON p.player_id = a.player_id AND datediff(a.event_date, p.login) = 1

Number of Unique Subjects Taught by Each Teacher - Easy

每位教师所教授的科目种类的数量:

1
2
3
4
5
6
7
8
9
10
Table: Teacher

+-------------+------+
| Column Name | Type |
+-------------+------+
| teacher_id | int |
| subject_id | int |
| dept_id | int |
+-------------+------+
(subject_id, dept_id) is the primary key

查询每位老师在大学里教授的科目种类的数量。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Input:
Teacher table:
+------------+------------+---------+
| teacher_id | subject_id | dept_id |
+------------+------------+---------+
| 1 | 2 | 3 |
| 1 | 2 | 4 |
| 1 | 3 | 3 |
| 2 | 1 | 1 |
| 2 | 2 | 1 |
| 2 | 3 | 1 |
| 2 | 4 | 1 |
+------------+------------+---------+
Output:
+------------+-----+
| teacher_id | cnt |
+------------+-----+
| 1 | 2 |
| 2 | 4 |
+------------+-----+
解释:
教师 1:
- 他在 3、4 系教科目 2。
- 他在 3 系教科目 3。
教师 2:
- 他在 1 系教科目 1。
- 他在 1 系教科目 2。
- 他在 1 系教科目 3。
- 他在 1 系教科目 4。
1
2
3
4
5
-- MySQL
SELECT teacher_id, COUNT(distinct subject_id) AS cnt
FROM teacher
GROUP BY teacher_id
;

User Activity for the Past 30 Days I - Easy

查询近 30 天活跃用户数:

1
2
3
4
5
6
7
8
9
10
11
Table: Activity

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| session_id | int |
| activity_date | date |
| activity_type | enum |
+---------------+---------+
There is no primary key for this table, it may have duplicate rows.

请写SQL查询出截至 2019-07-27(包含2019-07-27),近 30 天的每日活跃用户数(当天只要有一条活动记录,即为活跃用户)。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Input:
Activity table:
+---------+------------+---------------+---------------+
| user_id | session_id | activity_date | activity_type |
+---------+------------+---------------+---------------+
| 1 | 1 | 2019-07-20 | open_session |
| 1 | 1 | 2019-07-20 | scroll_down |
| 1 | 1 | 2019-07-20 | end_session |
| 2 | 4 | 2019-07-20 | open_session |
| 2 | 4 | 2019-07-21 | send_message |
| 2 | 4 | 2019-07-21 | end_session |
| 3 | 2 | 2019-07-21 | open_session |
| 3 | 2 | 2019-07-21 | send_message |
| 3 | 2 | 2019-07-21 | end_session |
| 4 | 3 | 2019-06-25 | open_session |
| 4 | 3 | 2019-06-25 | end_session |
+---------+------------+---------------+---------------+
Output:
+------------+--------------+
| day | active_users |
+------------+--------------+
| 2019-07-20 | 2 |
| 2019-07-21 | 2 |
+------------+--------------+
解释:注意非活跃用户的记录不需要展示。
1
2
3
4
5
6
-- MySQL
SELECT activity_date AS day, COUNT(DISTINCT(user_id)) AS active_users
FROM Activity
WHERE DATEDIFF('2019-7-27', activity_date) < 30 AND activity_date <= '2019-7-27'
GROUP BY activity_date
;

Sales Analysis III - Easy

销售分析III:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Table: Product

+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
| unit_price | int |
+--------------+---------+
product_id is the primary key

Table: Sales

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| seller_id | int |
| product_id | int |
| buyer_id | int |
| sale_date | date |
| quantity | int |
| price | int |
+-------------+---------+
This table has no primary key, it can have repeated rows.
product_id is a foreign key to the Product table.

编写一个SQL查询,报告2019年春季才售出的产品。即仅在2019-01-01至2019-03-31(含)之间出售的商品。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Input:
Product table:
+------------+--------------+------------+
| product_id | product_name | unit_price |
+------------+--------------+------------+
| 1 | S8 | 1000 |
| 2 | G4 | 800 |
| 3 | iPhone | 1400 |
+------------+--------------+------------+
Sales table:
+-----------+------------+----------+------------+----------+-------+
| seller_id | product_id | buyer_id | sale_date | quantity | price |
+-----------+------------+----------+------------+----------+-------+
| 1 | 1 | 1 | 2019-01-21 | 2 | 2000 |
| 1 | 2 | 2 | 2019-02-17 | 1 | 800 |
| 2 | 2 | 3 | 2019-06-02 | 1 | 800 |
| 3 | 3 | 4 | 2019-05-13 | 2 | 2800 |
+-----------+------------+----------+------------+----------+-------+
Output:
+-------------+--------------+
| product_id | product_name |
+-------------+--------------+
| 1 | S8 |
+-------------+--------------+

解释:
id为1的产品仅在2019年春季销售。
id为2的产品在2019年春季销售,但也在2019年春季之后销售。
id 3的产品在2019年春季之后销售。
我们只退回产品1,因为它是2019年春季才销售的产品。
1
2
3
4
5
6
7
8
9
-- MySQL
SELECT
sales.product_id AS product_id,
product.product_name AS product_name
FROM sales
LEFT JOIN product
ON sales.product_id = product.product_id
GROUP BY product_id
HAVING COUNT(sale_date BETWEEN '2019-01-01' AND '2019-03-31' OR NULL) = COUNT(*)

Classes More Than 5 Students - Easy

超过 5 名学生的课:

1
2
3
4
5
6
7
8
9
Table: Courses

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| student | varchar |
| class | varchar |
+-------------+---------+
(student, class) is the primary key column

编写一个SQL查询来报告 至少有5个学生 的所有班级。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Input:
Courses table:
+---------+----------+
| student | class |
+---------+----------+
| A | Math |
| B | English |
| C | Math |
| D | Biology |
| E | Math |
| F | Computer |
| G | Math |
| H | Math |
| I | Math |
+---------+----------+
Output:
+---------+
| class |
+---------+
| Math |
+---------+

解释:
-数学课有6个学生,所以我们包括它。
-英语课有1名学生,所以我们不包括它。
-生物课有1名学生,所以我们不包括它。
-计算机课有1个学生,所以我们不包括它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- MySQL
-- 方法一:使用 GROUP BY 子句和子查询
SELECT
class
FROM
(SELECT
class, COUNT(DISTINCT student) AS num
FROM
courses
GROUP BY class) AS temp_table
WHERE
num >= 5
;

-- 方法二:使用 GROUP BY 和 HAVING 条件
SELECT
class
FROM
courses
GROUP BY class
HAVING COUNT(DISTINCT student) >= 5
;

Find Followers Count - Easy

求关注者的数量:

1
2
3
4
5
6
7
8
9
Table: Followers

+-------------+------+
| Column Name | Type |
+-------------+------+
| user_id | int |
| follower_id | int |
+-------------+------+
(user_id, follower_id) is the primary key

对于每一个用户,返回该用户的关注者数量。

按 user_id 的顺序返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input:
Followers table:
+---------+-------------+
| user_id | follower_id |
+---------+-------------+
| 0 | 1 |
| 1 | 0 |
| 2 | 0 |
| 2 | 1 |
+---------+-------------+
Output:
+---------+----------------+
| user_id | followers_count|
+---------+----------------+
| 0 | 1 |
| 1 | 1 |
| 2 | 2 |
+---------+----------------+
解释:
0 的关注者有 {1}
1 的关注者有 {0}
2 的关注者有 {0,1}
1
2
3
4
5
6
-- MySQL
SELECT user_id, COUNT(*) AS followers_count
FROM followers
GROUP BY user_id
ORDER BY user_id
;

Biggest Single Number - Easy

只出现一次的最大数字:

1
2
3
4
5
6
7
8
Table: MyNumbers

+-------------+------+
| Column Name | Type |
+-------------+------+
| num | int |
+-------------+------+
There is no primary key

单一数字 是在 MyNumbers 表中只出现一次的数字。

请你编写一个 SQL 查询来报告最大的 单一数字 。如果不存在 单一数字 ,查询需报告 null 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input:
MyNumbers table:
+-----+
| num |
+-----+
| 8 |
| 8 |
| 3 |
| 3 |
| 1 |
| 4 |
| 5 |
| 6 |
+-----+
Output:
+-----+
| num |
+-----+
| 6 |
+-----+
解释:单一数字有 1、4、5 和 6 。
6 是最大的单一数字,返回 6 。
1
2
3
4
5
6
7
8
-- MySQL
SELECT MAX(num) AS num
FROM(SELECT num
FROM mynumbers
GROUP BY num
HAVING COUNT(num) = 1)
AS t
;

Customers Who Bought All Products - Medium

买下所有产品的客户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Table: Customer

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| customer_id | int |
| product_key | int |
+-------------+---------+
There is no primary key
product_key is a foreign key to Product table.

Table: Product

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_key | int |
+-------------+---------+
product_key is the primary key

从 Customer 表中查询购买了 Product 表中所有产品的客户的 id。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Input:
Customer table:
+-------------+-------------+
| customer_id | product_key |
+-------------+-------------+
| 1 | 5 |
| 2 | 6 |
| 3 | 5 |
| 3 | 6 |
| 1 | 6 |
+-------------+-------------+
Product table:
+-------------+
| product_key |
+-------------+
| 5 |
| 6 |
+-------------+
Output:
+-------------+
| customer_id |
+-------------+
| 1 |
| 3 |
+-------------+
购买了所有产品(5 和 6)的客户的 id 是 1 和 3 。
1
2
3
4
5
6
7
8
-- MySQL
SELECT customer_id
FROM customer
GROUP BY customer_id
HAVING COUNT(DISTINCT product_key) = (
SELECT COUNT(DISTINCT product_key)
FROM product
);

The Number of Employees Which Report to Each Employee - Easy

每位经理的下属员工数量:

1
2
3
4
5
6
7
8
9
10
11
Table: Employees

+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| reports_to | int |
| age | int |
+-------------+----------+
employee_id is the primary key

对于此问题,我们将至少有一个其他员工需要向他汇报的员工,视为一个经理。

编写SQL查询需要听取汇报的所有经理的ID、名称、直接向该经理汇报的员工人数,以及这些员工的平均年龄,其中该平均年龄需要四舍五入到最接近的整数。

返回的结果集需要按照 employee_id 进行排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Input:
Employees table:
+-------------+---------+------------+-----+
| employee_id | name | reports_to | age |
+-------------+---------+------------+-----+
| 9 | Hercy | null | 43 |
| 6 | Alice | 9 | 41 |
| 4 | Bob | 9 | 36 |
| 2 | Winston | null | 37 |
+-------------+---------+------------+-----+
Output:
+-------------+-------+---------------+-------------+
| employee_id | name | reports_count | average_age |
+-------------+-------+---------------+-------------+
| 9 | Hercy | 2 | 39 |
+-------------+-------+---------------+-------------+

Hercy 有两个需要向他汇报的员工, 他们是 Alice and Bob. 他们的平均年龄是 (41+36)/2 = 38.5, 四舍五入的结果是 39.
1
2
3
4
5
6
7
8
9
10
11
12
-- MySQL
SELECT
b.employee_id,
b.name,
COUNT(a.name) reports_count,
ROUND(AVG(a.age), 0) average_age
FROM Employees AS a
JOIN employees AS b
ON a.reports_to = b.employee_id
GROUP BY b.employee_id
ORDER BY b.employee_id
;

Primary Department for Each Employee - Easy

员工的直属部门:

1
2
3
4
5
6
7
8
9
10
Table: Employee

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| employee_id | int |
| department_id | int |
| primary_flag | varchar |
+---------------+---------+
(employee_id, department_id) is the primary key

当一个员工加入超过一个部门的时候,他需要决定哪个部门是他的直属部门。

请注意,当员工只加入一个部门的时候,那这个部门将默认为他的直属部门,虽然表记录的值为’N’.

请编写一段SQL,查出员工所属的直属部门。

返回结果没有顺序要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Input:
Employee table:
+-------------+---------------+--------------+
| employee_id | department_id | primary_flag |
+-------------+---------------+--------------+
| 1 | 1 | N |
| 2 | 1 | Y |
| 2 | 2 | N |
| 3 | 3 | N |
| 4 | 2 | N |
| 4 | 3 | Y |
| 4 | 4 | N |
+-------------+---------------+--------------+
Output:
+-------------+---------------+
| employee_id | department_id |
+-------------+---------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 3 |
+-------------+---------------+
Explanation:
- The Primary department for employee 1 is 1.
- The Primary department for employee 2 is 1.
- The Primary department for employee 3 is 3.
- The Primary department for employee 4 is 3.
1
2
3
4
5
6
7
8
9
10
-- MySQL
SELECT employee_id, department_id
FROM employee
GROUP BY employee_id
HAVING COUNT(department_id) = 1
UNION
SELECT employee_id, department_id
FROM employee
WHERE primary_flag = 'Y'
;

Triangle Judgement - Easy

判断三角形:

1
2
3
4
5
6
7
8
9
10
Table: Triangle

+-------------+------+
| Column Name | Type |
+-------------+------+
| x | int |
| y | int |
| z | int |
+-------------+------+
(x, y, z) is the primary key

写一个SQL查询,每三个线段报告它们是否可以形成一个三角形。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Input:
Triangle table:
+----+----+----+
| x | y | z |
+----+----+----+
| 13 | 15 | 30 |
| 10 | 20 | 15 |
+----+----+----+
Output:
+----+----+----+----------+
| x | y | z | triangle |
+----+----+----+----------+
| 13 | 15 | 30 | No |
| 10 | 20 | 15 | Yes |
+----+----+----+----------+
1
2
3
4
5
6
7
8
9
10
11
-- MySQL
SELECT
x,
y,
z,
CASE
WHEN x + y > z AND x + z > y AND y + z > x THEN 'Yes'
ELSE 'No'
END AS 'triangle'
FROM triangle
;

Consecutive Numbers - Medium

连续出现的数字:

1
2
3
4
5
6
7
8
9
10
Table: Logs

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| num | varchar |
+-------------+---------+
id is the primary key for this table.
id is an autoincrement column.

编写一个 SQL 查询,查找所有至少连续出现三次的数字。

返回的结果表中的数据可以按 任意顺序 排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Input:
Logs table:
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
Output:
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
Explanation: 1 is the only number that appears consecutively for at least three times.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- MySQL
SELECT DISTINCT
l1.num AS ConsecutiveNums
FROM
Logs l1,
Logs l2,
Logs l3
WHERE
l1.id = l2.id - 1
AND
l2.id = l3.id - 1
AND
l1.num = l2.num
AND
l2.num = l3.num
;

Product Price at a Given Date - Medium

指定日期的产品价格:

1
2
3
4
5
6
7
8
9
10
Table: Products

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| new_price | int |
| change_date | date |
+---------------+---------+
(product_id, change_date) is the primary key

写一段 SQL来查找在 2019-08-16 时全部产品的价格,假设所有产品在修改前的价格都是 10 。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Input:
Products table:
+------------+-----------+-------------+
| product_id | new_price | change_date |
+------------+-----------+-------------+
| 1 | 20 | 2019-08-14 |
| 2 | 50 | 2019-08-14 |
| 1 | 30 | 2019-08-15 |
| 1 | 35 | 2019-08-16 |
| 2 | 65 | 2019-08-17 |
| 3 | 20 | 2019-08-18 |
+------------+-----------+-------------+
Output:
+------------+-------+
| product_id | price |
+------------+-------+
| 2 | 50 |
| 1 | 35 |
| 3 | 10 |
+------------+-------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- MySQL
SELECT
p1.product_id,
IFNULL(p2.new_price, 10) AS price
FROM (
SELECT DISTINCT product_id
FROM products
) AS p1
LEFT JOIN (
SELECT product_id, new_price
FROM products
WHERE (product_id, change_date) IN (
SELECT product_id, MAX(change_date)
FROM products
WHERE change_date <= '2019-08-16'
GROUP BY product_id
)
) AS p2
ON p1.product_id = p2.product_id
;

Last Person to Fit in the Bus - Medium

最后一个能进入电梯的人:

1
2
3
4
5
6
7
8
9
10
11
Table: Queue

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| person_id | int |
| person_name | varchar |
| weight | int |
| turn | int |
+-------------+---------+
person_id is the primary key

有一群人在等着上公共汽车。然而,巴士有 1000 公斤的重量限制,所以可能会有一些人不能上。

写一条 SQL 查询语句查找 最后一个 能进入电梯且不超过重量限制的 person_name 。题目确保队列中第一位的人可以进入电梯,不会超重。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input:
Queue table:
+-----------+-------------+--------+------+
| person_id | person_name | weight | turn |
+-----------+-------------+--------+------+
| 5 | Alice | 250 | 1 |
| 4 | Bob | 175 | 5 |
| 3 | Alex | 350 | 2 |
| 6 | John Cena | 400 | 3 |
| 1 | Winston | 500 | 6 |
| 2 | Marie | 200 | 4 |
+-----------+-------------+--------+------+
Output:
+-------------+
| person_name |
+-------------+
| John Cena |
+-------------+
解释:
为了简化,Queue 表按 turn 列由小到大排序。
上例中 George Washington(id 5), John Adams(id 3) 和 Thomas Jefferson(id 6) 将可以进入电梯,因为他们的体重和为 250 + 350 + 400 = 1000。
Thomas Jefferson(id 6) 是最后一个体重合适并进入电梯的人。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- MySQL
-- 方法一:自连接
SELECT a.person_name
FROM Queue a, Queue b
WHERE a.turn >= b.turn
GROUP BY a.person_id
HAVING SUM(b.weight) <= 1000
ORDER BY a.turn DESC
LIMIT 1
;

-- 方法二:自定义变量
SELECT a.person_name
FROM (
SELECT
person_name,
@pre := @pre + weight AS weight
FROM
queue,
(SELECT @pre := 0) AS tmp
ORDER BY turn
) AS a
WHERE a.weight <= 1000
ORDER BY a.weight DESC
LIMIT 1
;

Count Salary Categories - Medium

按分类统计薪水:

1
2
3
4
5
6
7
8
9
Table: Accounts

+-------------+------+
| Column Name | Type |
+-------------+------+
| account_id | int |
| income | int |
+-------------+------+
account_id is the primary key

写出一个 SQL 查询,来报告每个工资类别的银行账户数量。 工资类别如下:

“Low Salary”:所有工资 严格低于 20000 美元。
“Average Salary”: 包含 范围内的所有工资 [$20000, $50000] 。
“High Salary”:所有工资 严格大于 50000 美元。

结果表 必须 包含所有三个类别。如果某个类别中没有帐户,则报告 0。

按 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Input:
Accounts table:
+------------+--------+
| account_id | income |
+------------+--------+
| 3 | 108939 |
| 2 | 12747 |
| 8 | 87709 |
| 6 | 91796 |
+------------+--------+

Output:
+----------------+----------------+
| category | accounts_count |
+----------------+----------------+
| Low Salary | 1 |
| Average Salary | 0 |
| High Salary | 3 |
+----------------+----------------+
Explanation:
Low Salary: Account 2.
Average Salary: No accounts.
High Salary: Accounts 3, 6, and 8.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- MySQL
SELECT
'Low Salary' category,
SUM(income < 20000) accounts_count
FROM accounts
UNION ALL
SELECT
'Average Salary',
SUM(income >= 20000 AND income <= 50000)
FROM accounts
UNION ALL
SELECT
'High Salary',
SUM(income > 50000)
FROM accounts
;

Employees Whose Manager Left the Company - Easy

上级经理已离职的公司员工

1
2
3
4
5
6
7
8
9
10
11
12
13
Table: Employees

+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| manager_id | int |
| salary | int |
+-------------+----------+

employee_id is the primary key
Some employees do not have a manager (manager_id is null)

查找这些员工的id,他们的薪水严格少于$30000 并且他们的上级经理已离职。当一个经理离开公司时,他们的信息需要从员工表中删除掉,但是表中的员工的manager_id 这一列还是设置的离职经理的id 。

返回的结果按照employee_id 从小到大排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Input:
Employees table:
+-------------+-----------+------------+--------+
| employee_id | name | manager_id | salary |
+-------------+-----------+------------+--------+
| 3 | Mila | 9 | 60301 |
| 12 | Antonella | null | 31000 |
| 13 | Emery | null | 67084 |
| 1 | Kalel | 11 | 21241 |
| 9 | Mikaela | null | 50937 |
| 11 | Joziah | 6 | 28485 |
+-------------+-----------+------------+--------+
Output:
+-------------+
| employee_id |
+-------------+
| 11 |
+-------------+

Explanation:
薪水少于 30000 美元的员工有 1 号(Kalel) 和 11号 (Joziah)。
Kalel 的上级经理是 11 号员工,他还在公司上班(他是 Joziah )。
Joziah 的上级经理是 6 号员工,他已经离职,因为员工表里面已经没有 6 号员工的信息了,它被删除了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- MySQL
--方法一:左连接
select e1.employee_id
from Employees e1
left join Employees e2
on e1.manager_id = e2.employee_id
where e1.salary < 30000 and e1.manager_id is not null and e2.employee_id is null
order by e1.employee_id

--方法二:not in + 子查询
select employee_id
from Employees
where salary < 30000
and manager_id not in (select employee_id from Employees)
order by employee_id

Exchange Seats - Medium

1
2
3
4
5
6
7
8
9
10
Table: Seat

+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| student | varchar |
+-------------+---------+
id is the primary key (unique value) column
id is a continuous increment. 「连续增量」

编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。

按 id 升序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Input:
Seat table:
+----+---------+
| id | student |
+----+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+----+---------+
Output:
+----+---------+
| id | student |
+----+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+----+---------+
Explanation:
如果学生人数为奇数,则不需要更换最后一名学生的座位。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-- MySQL
方法一:使用 CASE
SELECT
COUNT(*) AS counts
FROM
seat

SELECT
(CASE
WHEN MOD(id, 2) != 0 AND counts != id THEN id + 1
WHEN MOD(id, 2) != 0 AND counts = id THEN id
ELSE id - 1
END) AS id,
student
FROM
seat,
(SELECT
COUNT(*) AS counts
FROM
seat) AS seat_counts
ORDER BY id ASC;

方法二:使用位操作和 COALESCE()
SELECT id, (id+1)^1-1, student FROM seat;

SELECT
*
FROM
seat s1
LEFT JOIN
seat s2 ON (s1.id+1)^1-1 = s2.id
ORDER BY s1.id;

SELECT
s1.id, COALESCE(s2.student, s1.student) AS student
FROM
seat s1
LEFT JOIN
seat s2 ON ((s1.id + 1) ^ 1) - 1 = s2.id
ORDER BY s1.id;

Movie Rating - Medium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Table: Movies

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| title | varchar |
+---------------+---------+
movie_id is the primary key

Table: Users

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| name | varchar |
+---------------+---------+
user_id is the primary key

Table: MovieRating

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| user_id | int |
| rating | int |
| created_at | date |
+---------------+---------+
(movie_id, user_id) is the primary key

查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
查找在 February 2020 平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称。

字典序 ,即按字母在字典中出现顺序对字符串排序,字典序较小则意味着排序靠前。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Input:
Movies table:
+-------------+--------------+
| movie_id | title |
+-------------+--------------+
| 1 | Avengers |
| 2 | Frozen 2 |
| 3 | Joker |
+-------------+--------------+
Users table:
+-------------+--------------+
| user_id | name |
+-------------+--------------+
| 1 | Daniel |
| 2 | Monica |
| 3 | Maria |
| 4 | James |
+-------------+--------------+
MovieRating table:
+-------------+--------------+--------------+-------------+
| movie_id | user_id | rating | created_at |
+-------------+--------------+--------------+-------------+
| 1 | 1 | 3 | 2020-01-12 |
| 1 | 2 | 4 | 2020-02-11 |
| 1 | 3 | 2 | 2020-02-12 |
| 1 | 4 | 1 | 2020-01-01 |
| 2 | 1 | 5 | 2020-02-17 |
| 2 | 2 | 2 | 2020-02-01 |
| 2 | 3 | 2 | 2020-03-01 |
| 3 | 1 | 3 | 2020-02-22 |
| 3 | 2 | 4 | 2020-02-25 |
+-------------+--------------+--------------+-------------+
Output:
+--------------+
| results |
+--------------+
| Daniel |
| Frozen 2 |
+--------------+
Explanation:
Daniel 和 Monica 都点评了 3 部电影("Avengers", "Frozen 2" 和 "Joker") 但是 Daniel 字典序比较小。
Frozen 2 和 Joker 在 2 月的评分都是 3.5,但是 Frozen 2 的字典序比较小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- MySQL
# 评论电影数量最多且字典序较小的用户名
(
select Users.name as results
FROM MovieRating
JOIN Users ON MovieRating.user_id = Users.user_id
GROUP BY MovieRating.user_id
ORDER BY
count(MovieRating.user_id) desc,
Users.name
LIMIT 1
)
UNION ALL(
# 20202月份平均评分最高且字典序较小的电影名
select
Movies.title as results
FROM MovieRating
JOIN Movies ON MovieRating.movie_id = Movies.movie_id
WHERE
MovieRating.created_at >= '2020-02-01'
AND MovieRating.created_at < '2020-03-01'
GROUP BY MovieRating.movie_id
ORDER BY
avg(MovieRating.rating) desc,
Movies.title
LIMIT 1
)

Restaurant Growth - Medium

餐馆营业额变化增长

1
2
3
4
5


该表包含一家餐馆的顾客交易数据。
visited_on 表示 (customer_id) 的顾客在 visited_on 那天访问了餐馆。
amount 是一个顾客某一天的消费总额。

分析一下可能的营业额变化增长(每天至少有一位顾客)。

计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值。average_amount 要 保留两位小数。

结果按 visited_on 升序排序。

1
2
3
4
5
6


第一个七天消费平均值从 2019-01-01 到 2019-01-07 是restaurant-growth/restaurant-growth/ (100 + 110 + 120 + 130 + 110 + 140 + 150)/7 = 122.86
第二个七天消费平均值从 2019-01-02 到 2019-01-08 是 (110 + 120 + 130 + 110 + 140 + 150 + 80)/7 = 120
第三个七天消费平均值从 2019-01-03 到 2019-01-09 是 (120 + 130 + 110 + 140 + 150 + 80 + 110)/7 = 120
第四个七天消费平均值从 2019-01-04 到 2019-01-10 是 (130 + 110 + 140 + 150 + 80 + 110 + 130 + 150)/7 = 142.86

好友申请 II :谁有最多的好友

1
2
3



找出拥有最多的好友的人和他拥有的好友数目。

生成的测试用例保证拥有最多好友数目的只有 1 个人。

1
2

编号为 3 的人是编号为 1 ,2 和 4 的人的好友,所以他总共有 3 个好友,比其他人都多。

1
2
3
4
5
6
7


表中的每一行都包含一条保险信息,其中:
pid 是投保人的投保编号。
tiv_2015 是该投保人在 2015 年的总投保金额,tiv_2016 是该投保人在 2016 年的总投保金额。
lat 是投保人所在城市的纬度。题目数据确保 lat 不为空。
lon 是投保人所在城市的经度。题目数据确保 lon 不为空。

报告 2016 年 (tiv_2016) 所有满足下述条件的投保人的投保金额之和:

他在 2015 年的投保额 (tiv_2015) 至少跟一个其他投保人在 2015 年的投保额相同。
他所在的城市必须与其他投保人都不同(也就是说 (lat, lon) 不能跟其他任何一个投保人完全相同)。
tiv_2016 四舍五入的 两位小数 。

1
2
3
4
5
6
7


表中的第一条记录和最后一条记录都满足两个条件。
tiv_2015 值为 10 与第三条和第四条记录相同,且其位置是唯一的。

第二条记录不符合任何一个条件。其 tiv_2015 与其他投保人不同,并且位置与第三条记录相同,这也导致了第三条记录不符合题目要求。
因此,结果是第一条记录和最后一条记录的 tiv_2016 之和,即 45 。

公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者 是指一个员工的工资在该部门的 不同 工资中 排名前三 。

编写解决方案,找出每个部门中 收入高的员工 。

以 任意顺序 返回结果表。

1
2
3
4
5
6
7
8
9
10
11


在IT部门:
- Max的工资最高
- 兰迪和乔都赚取第二高的独特的薪水
- 威尔的薪水是第三高的

在销售部:
- 亨利的工资最高
- 山姆的薪水第二高
- 没有第三高的工资,因为只有两名员工

修复表中的名字

1
2
3


该表包含用户的 ID 和名字。名字仅由小写和大写字符组成。

修复名字,使得只有第一个字符是大写的,其余都是小写的。

返回按 user_id 排序的结果表。

1

患某种疾病的患者

1
2
3


'conditions' (疾病)包含 0 个或以上的疾病代码,以空格分隔。

查询患有 I 类糖尿病的患者 ID (patient_id)、患者姓名(patient_name)以及其患有的所有疾病代码(conditions)。I 类糖尿病的代码总是包含前缀 DIAB1 。

按 任意顺序 返回结果表。

1
2
3


Bob 和 George 都患有代码以 DIAB1 开头的疾病。

删除重复的电子邮箱

1
2
3


该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。

删除 所有重复的电子邮件,只保留一个具有最小 id 的唯一电子邮件。

(对于 SQL 用户,请注意你应该编写一个 DELETE 语句而不是 SELECT 语句。)

(对于 Pandas 用户,请注意你应该直接修改 Person 表。)

运行脚本后,显示的答案是 Person 表。驱动程序将首先编译并运行您的代码片段,然后再显示 Person 表。Person 表的最终顺序 无关紧要 。

1
2
3


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

第二高的薪水

1

查询并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null(Pandas 则返回 None) 。

1

按日期分组销售产品

1

找出每个日期、销售的不同产品的数量及其名称。
每个日期的销售产品名称应按词典序排列。
返回按 sell_date 排序的结果表。

1
2
3
4
5


对于2020-05-30,出售的物品是 (Headphone, Basketball, T-shirt),按词典序排列,并用逗号 ',' 分隔。
对于2020-06-01,出售的物品是 (Pencil, Bible),按词典序排列,并用逗号分隔。
对于2020-06-02,出售的物品是 (Mask),只需返回该物品名。

列出指定时间段内所有的下单产品

1
2
3
4


该表可能包含重复行。
unit 是在日期 order_date 内下单产品的数目。

获取在 2020 年 2 月份下单的数量不少于 100 的产品的名字和数目。

返回结果表单的 顺序无要求 。

1
2
3
4
5
6
7


2020 年 2 月份下单 product_id = 1 的产品的数目总和为 (60 + 70) = 130 。
2020 年 2 月份下单 product_id = 2 的产品的数目总和为 80 。
2020 年 2 月份下单 product_id = 3 的产品的数目总和为 (2 + 3) = 5 。
2020 年 2 月份 product_id = 4 的产品并没有下单。
2020 年 2 月份下单 product_id = 5 的产品的数目总和为 (50 + 50) = 100 。

查找拥有有效邮箱的用户

1
2
3


该表包含了网站已注册用户的信息。有一些电子邮件是无效的。

查找具有有效电子邮件的用户。

一个有效的电子邮件具有前缀名称和域,其中:

前缀 名称是一个字符串,可以包含字母(大写或小写),数字,下划线 ‘_’ ,点 ‘.’ 和/或破折号 ‘-‘ 。前缀名称 必须 以字母开头。
域 为 ‘@leetcode.com’ 。
以任何顺序返回结果表。

1
2
3
4
5
6


用户 2 的电子邮件没有域。
用户 5 的电子邮件带有不允许的 '#' 符号。
用户 6 的电子邮件没有 leetcode 域。
用户 7 的电子邮件以点开头。

Refer

「新」动计划 · 编程入门
高频 SQL 50 题(基础版)
LeetCode 热题 100
算法通关手册
代码随想录
1.初级算法
2.数组类算法
3.数组和字符串
4.链表图文学
5.队列 & 栈图文学
6.二分查找
7.二叉树
8.二叉搜索树
9.N 叉树
10.前缀树
11.中级算法
12.高级算法
13.动态规划路径问题
14.算法面试题汇总
2020 名企高频面试题
图解算法数据结构
设计数据结构
数据结构教程(第 6 版) - 在线编程实训
CodeTop 企业题库

PS

期待有一天 LeetCode 基本刷遍……

 Comments