題目一
小美是一所中學的信息科技老師,她有一張 seat 座位表,平時用來儲存學生名字和與他們相對應的座位 id。
其中縱列的 id 是連續遞增的
小美想改變相鄰倆學生的座位。
你能不能幫她寫一個 SQL query 來輸出小美想要的結果呢?
示例:
±--------±--------+
| id | student |
±--------±--------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
±--------±--------+
假如數據輸入的是上表,則輸出結果如下:
±--------±--------+
| id | student |
±--------±--------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
±--------±--------+
注意:
如果學生人數是奇數,則不需要改變最後一個同學的座位。
SELECT if(id%2=1,
if(id=@a,
id,
id+1),
id-1) id,
student
FROM seat s,
(SELECT @a:=count(id)
FROM seat) ret
ORDER BY id;
題目二
在 Facebook 或者 Twitter 這樣的社交應用中,人們經常會發好友申請也會收到其他人的好友申請。
表 request_accepted 存儲了所有好友申請通過的數據記錄,其中, requester_id 和 accepter_id 都是用戶的編號。
| requester_id | accepter_id | accept_date|
|--------------|-------------|------------|
| 1 | 2 | 2016_06-03 |
| 1 | 3 | 2016-06-08 |
| 2 | 3 | 2016-06-08 |
| 3 | 4 | 2016-06-09 |
寫一個查詢語句,求出誰擁有最多的好友和他擁有的好友數目。對於上面的樣例數據,結果爲:
| id | num |
|----|-----|
| 3 | 3 |
注意:
保證擁有最多好友數目的只有 1 個人。
好友申請只會被接受一次,所以不會有 requester_id 和 accepter_id 值都相同的重複記錄。
解釋:
編號爲 ‘3’ 的人是編號爲 ‘1’,‘2’ 和 ‘4’ 的好友,所以他總共有 3 個好友,比其他人都多。
進階:
在真實世界裏,可能會有多個人擁有好友數相同且最多,你能找到所有這些人嗎?
SELECT id AS id,
ucnt AS num
FROM
(SELECT id,
count(1) AS ucnt
FROM
(SELECT requester_id AS id
FROM request_accepted
UNION
allSELECT accepter_id AS id
FROM request_accepted )
GROUP BY id
ORDER BY ucnt DESC )
WHERE rownum = 1
題目三
表 point_2d 保存了所有點(多於 2 個點)的座標 (x,y) ,這些點在平面上兩兩不重合。
寫一個查詢語句找到兩點之間的最近距離,保留 2 位小數。
| x | y |
|----|----|
| -1 | -1 |
| 0 | 0 |
| -1 | -2 |
最近距離在點 (-1,-1) 和(-1,2) 之間,距離爲 1.00 。所以輸出應該爲:
| shortest |
|----------|
| 1.00 |
注意:任意點之間的最遠距離小於 10000 。
SELECT ROUND(MIN(shortest),
2) shortest FROM
(SELECT POWER(POWER((p1.x-p2.x),
2)+POWER((p1.y-p2.y),
2),
0.5) shortest
FROM point_2d p1,point_2d p2
WHERE p1.x !=p2.x
OR p1.y != p2.y )a
題目四
編寫一個 SQL 查詢來實現分數排名。如果兩個分數相同,則兩個分數排名(Rank)相同。請注意,平分後的下一個名次應該是下一個連續的整數值。換句話說,名次之間不應該有“間隔”。
±—±------+
| Id | Score |
±—±------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
±—±------+
例如,根據上述給定的 Scores 表,你的查詢應該返回(按分數從高到低排列):
±------±-----+
| Score | Rank |
±------±-----+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
±------±-----+
SELECT a.Score,
sum(case
WHEN b.Score>=a.Score THEN
1 end) AS Rank
FROM Scores a,
(SELECT DISTINCT Score
FROM Scores ) b
GROUP BY a.id
ORDER BY a.Score desc;
題目五
給定一個表 tree,id 是樹節點的編號, p_id 是它父節點的 id 。
±—±-----+
| id | p_id |
±—±-----+
| 1 | null |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
±—±-----+
樹中每個節點屬於以下三種類型之一:
葉子:如果這個節點沒有任何孩子節點。
根:如果這個節點是整棵樹的根,即沒有父節點。
內部節點:如果這個節點既不是葉子節點也不是根節點。
寫一個查詢語句,輸出所有節點的編號和節點的類型,並將結果按照節點編號排序。上面樣例的結果爲:
±—±-----+
| id | Type |
±—±-----+
| 1 | Root |
| 2 | Inner|
| 3 | Leaf |
| 4 | Leaf |
| 5 | Leaf |
±—±-----+
解釋
節點 ‘1’ 是根節點,因爲它的父節點是 NULL ,同時它有孩子節點 ‘2’ 和 ‘3’ 。
節點 ‘2’ 是內部節點,因爲它有父節點 ‘1’ ,也有孩子節點 ‘4’ 和 ‘5’ 。
節點 ‘3’, ‘4’ 和 ‘5’ 都是葉子節點,因爲它們都有父節點同時沒有孩子節點。
樣例中樹的形態如下:
1
/ \
2 3
/ \
4 5
SELECT DISTINCT t1.id,
(CASE
WHEN t1.p_id IS NULL THEN
'Root' ELSE
CASE
WHEN t2.id IS NULL THEN
'Leaf'
ELSE 'Inner'
END END) AS Type
FROM tree t1
LEFT JOIN tree t2
ON t1.id=t2.p_id
題目六
Employee 表包含所有員工和他們的經理。每個員工都有一個 Id,並且還有一列是經理的 Id。
±-----±---------±----------±---------+
|Id |Name |Department |ManagerId |
±-----±---------±----------±---------+
|101 |John |A |null |
|102 |Dan |A |101 |
|103 |James |A |101 |
|104 |Amy |A |101 |
|105 |Anne |A |101 |
|106 |Ron |B |101 |
±-----±---------±----------±---------+
給定 Employee 表,請編寫一個SQL查詢來查找至少有5名直接下屬的經理。對於上表,您的SQL查詢應該返回:
±------+
| Name |
±------+
| John |
±------+
SELECT b.Name
FROM employee a
INNER JOIN employee b
ON a.managerid= b.id
GROUP BY a.managerid
HAVING count(*)>=5;
題目七
一所大學有 2 個數據表,分別是 student 和 department ,這兩個表保存着每個專業的學生數據和院系數據。
寫一個查詢語句,查詢 department 表中每個專業的學生人數 (即使沒有學生的專業也需列出)。
將你的查詢結果按照學生人數降序排列。 如果有兩個或兩個以上專業有相同的學生數目,將這些部門按照部門名字的字典序從小到大排列。
student 表格如下:
| Column Name | Type |
|--------------|-----------|
| student_id | Integer |
| student_name | String |
| gender | Character |
| dept_id | Integer |
其中, student_id 是學生的學號, student_name 是學生的姓名, gender 是學生的性別, dept_id 是學生所屬專業的專業編號。
department 表格如下:
| Column Name | Type |
|-------------|---------|
| dept_id | Integer |
| dept_name | String |
dept_id 是專業編號, dept_name 是專業名字。
這裏是一個示例輸入:
student 表格:
| student_id | student_name | gender | dept_id |
|------------|--------------|--------|---------|
| 1 | Jack | M | 1 |
| 2 | Jane | F | 1 |
| 3 | Mark | M | 2 |
department 表格:
| dept_id | dept_name |
|---------|-------------|
| 1 | Engineering |
| 2 | Science |
| 3 | Law |
示例輸出爲:
| dept_name | student_number |
|-------------|----------------|
| Engineering | 2 |
| Science | 1 |
| Law | 0 |
SELECT dept_name,
(case
WHEN student_num is NULL THEN
0
ELSE student_num end) student_number
FROM
(SELECT dept_id,
count(*) student_num
FROM student
GROUP BY dept_id) t1
RIGHT JOIN department t2
ON t1.dept_id=t2.dept_id
ORDER BY student_number desc,dept_name asc
題目八
寫一個查詢語句,將 2016 年 (TIV_2016) 所有成功投資的金額加起來,保留 2 位小數。
對於一個投保人,他在 2016 年成功投資的條件是:
他在 2015 年的投保額 (TIV_2015) 至少跟一個其他投保人在 2015 年的投保額相同。
他所在的城市必須與其他投保人都不同(也就是說維度和經度不能跟其他任何一個投保人完全相同)。
輸入格式:
表 insurance 格式如下:
| Column Name | Type |
|-------------|---------------|
| PID | INTEGER(11) |
| TIV_2015 | NUMERIC(15,2) |
| TIV_2016 | NUMERIC(15,2) |
| LAT | NUMERIC(5,2) |
| LON | NUMERIC(5,2) |
PID 字段是投保人的投保編號, TIV_2015 是該投保人在2015年的總投保金額, TIV_2016 是該投保人在2016年的投保金額, LAT 是投保人所在城市的維度, LON 是投保人所在城市的經度。
樣例輸入
| PID | TIV_2015 | TIV_2016 | LAT | LON |
|-----|----------|----------|-----|-----|
| 1 | 10 | 5 | 10 | 10 |
| 2 | 20 | 20 | 20 | 20 |
| 3 | 10 | 30 | 20 | 20 |
| 4 | 10 | 40 | 40 | 40 |
樣例輸出
| TIV_2016 |
|----------|
| 45.00 |
解釋
就如最後一個投保人,第一個投保人同時滿足兩個條件:
1. 他在 2015 年的投保金額 TIV_2015 爲 ‘10’ ,與第三個和第四個投保人在 2015 年的投保金額相同。
2. 他所在城市的經緯度是獨一無二的。
第二個投保人兩個條件都不滿足。他在 2015 年的投資 TIV_2015 與其他任何投保人都不相同。
且他所在城市的經緯度與第三個投保人相同。基於同樣的原因,第三個投保人投資失敗。
所以返回的結果是第一個投保人和最後一個投保人的 TIV_2016 之和,結果是 45 。
SELECT sum(case
WHEN t3.TIV_2015 is NOT NULL THEN
t2.TIV_2016
ELSE 0 end) TIV_2016 from
(SELECT TIV_2015
FROM insurance
GROUP BY TIV_2015
HAVING count(TIV_2015)>1)t3
RIGHT JOIN
(SELECT *
FROM insurance
GROUP BY LAT, LON
HAVING count(LAT) = 1
AND count(LON) = 1) t2
ON t2.TIV_2015=t3.TIV_2015
題目九
Customer 表:
±------------±--------+
| Column Name | Type |
±------------±--------+
| customer_id | int |
| product_key | int |
±------------±--------+
product_key 是 Product 表的外鍵。
Product 表:
±------------±--------+
| Column Name | Type |
±------------±--------+
| product_key | int |
±------------±--------+
product_key 是這張表的主鍵。
寫一條 SQL 查詢語句,從 Customer 表中查詢購買了 Product 表中所有產品的客戶的 id。
示例:
Customer 表:
±------------±------------+
| customer_id | product_key |
±------------±------------+
| 1 | 5 |
| 2 | 6 |
| 3 | 5 |
| 3 | 6 |
| 1 | 6 |
±------------±------------+
Product 表:
±------------+
| product_key |
±------------+
| 5 |
| 6 |
±------------+
Result 表:
±------------+
| customer_id |
±------------+
| 1 |
| 3 |
±------------+
購買了所有產品(5 和 6)的客戶的 id 是 1 和 3 。
SELECT customer_id
FROM
(SELECT DISTINCT c.customer_id,
c.product_key AS cpk,
p.product_key AS ppk
FROM customer c
LEFT JOIN product p
ON c.product_key=p.product_key) tmp
GROUP BY customer_id
HAVING COUNT(cpk) =
(SELECT COUNT(product_key)
FROM product)
AND COUNT(ppk) =
(SELECT COUNT(product_key)
FROM product)
題目十
編寫一個 SQL 查詢,查找所有至少連續出現三次的數字。
±—±----+
| Id | Num |
±—±----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
±—±----+
例如,給定上面的 Logs 表, 1 是唯一連續出現至少三次的數字。
±----------------+
| ConsecutiveNums |
±----------------+
| 1 |
±----------------+
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 ;
題目十一
表: Candidate
±----±--------+
| id | Name |
±----±--------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
±----±--------+
表: Vote
±----±-------------+
| id | CandidateId |
±----±-------------+
| 1 | 2 |
| 2 | 4 |
| 3 | 3 |
| 4 | 2 |
| 5 | 5 |
±----±-------------+
id 是自動遞增的主鍵,
CandidateId 是 Candidate 表中的 id.
請編寫 sql 語句來找到當選者的名字,上面的例子將返回當選者 B.
±-----+
| Name |
±-----+
| B |
±-----+
注意:
你可以假設沒有平局,換言之,最多隻有一位當選者。
elect t3.name Name
FROM Candidate t3,
(SELECT t1.CandidateId CandidateId
FROM Vote t1
GROUP BY t1.CandidateId
ORDER BY count(*) DESC limit 1)t2
WHERE t3.id=t2.CandidateId
題目十二
Employee 表包含所有員工信息,每個員工有其對應的 Id, salary 和 department Id。
±—±------±-------±-------------+
| Id | Name | Salary | DepartmentId |
±—±------±-------±-------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
±—±------±-------±-------------+
Department 表包含公司所有部門的信息。
±—±---------+
| Id | Name |
±—±---------+
| 1 | IT |
| 2 | Sales |
±—±---------+
編寫一個 SQL 查詢,找出每個部門工資最高的員工。例如,根據上述給定的表格,Max 在 IT 部門有最高工資,Henry 在 Sales 部門有最高工資。
±-----------±---------±-------+
| Department | Employee | Salary |
±-----------±---------±-------+
| IT | Max | 90000 |
| Sales | Henry | 80000 |
±-----------±---------±-------+
SELECT Department.name AS 'Department', Employee.name AS 'Employee', Salary
FROM Employee
JOIN Department
ON Employee.DepartmentId = Department.Id
WHERE (Employee.DepartmentId , Salary) IN
(SELECT DepartmentId,
MAX(Salary)
FROM Employee
GROUP BY DepartmentId ) ;
題目十三
從 survey_log 表中獲得回答率最高的問題,survey_log 表包含這些列:uid, action, question_id, answer_id, q_num, timestamp。
uid 表示用戶 id;action 有以下幾種值:“show”,“answer”,“skip”;當 action 值爲 “answer” 時 answer_id 非空,而 action 值爲 “show” 或者 “skip” 時 answer_id 爲空;q_num 表示當前會話中問題的編號。
請編寫SQL查詢來找到具有最高回答率的問題。
示例:
輸入:
±-----±----------±-------------±-----------±----------±-----------+
| uid | action | question_id | answer_id | q_num | timestamp |
±-----±----------±-------------±-----------±----------±-----------+
| 5 | show | 285 | null | 1 | 123 |
| 5 | answer | 285 | 124124 | 1 | 124 |
| 5 | show | 369 | null | 2 | 125 |
| 5 | skip | 369 | null | 2 | 126 |
±-----±----------±-------------±-----------±----------±-----------+
輸出:
±------------+
| survey_log |
±------------+
| 285 |
±------------+
解釋:
問題285的回答率爲 1/1,而問題369回答率爲 0/1,因此輸出285。
注意: 回答率最高的含義是:同一問題編號中回答數佔顯示數的比例。
SELECT question_id AS survey_log
FROM survey_log
GROUP BY question_id
ORDER BY ( ifnull( count( answer_id ), 0 ) / count( * ) ) DESC LIMIT 1
題目十四
在 facebook 中,表 follow 會有 2 個字段: followee, follower ,分別表示被關注者和關注者。
請寫一個 sql 查詢語句,對每一個關注者,查詢他的關注者數目。
比方說:
±------------±-----------+
| followee | follower |
±------------±-----------+
| A | B |
| B | C |
| B | D |
| D | E |
±------------±-----------+
應該輸出:
±------------±-----------+
| follower | num |
±------------±-----------+
| B | 2 |
| D | 1 |
±------------±-----------+
解釋:
B 和 D 都在在 follower 字段中出現,作爲被關注者,B 被 C 和 D 關注,D 被 E 關注。A 不在 follower 字段內,所以A不在輸出列表中。
注意:
被關注者永遠不會被他 / 她自己關注。
將結果按照字典序返回。
SELECT f1.follower AS follower,
count(distinct f2.follower) AS num
FROM follow f1, follow f2
WHERE f1.follower = f2.followee
GROUP BY f1.follower
ORDER BY f1.follower