項目十六 分數排名 (難度:中等)
依然是昨天的分數表,實現排名功能,但是排名需要是非連續的,如下:
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 3 |
| 3.65 | 4 |
| 3.65 | 4 |
| 3.50 | 6 |
+-------+------
項目十七:查詢回答率最高的問題 (難度:中等)
求出survey_log表中回答率最高的問題,表格的字段有:uid, action, question_id, answer_id, q_num, timestamp。
uid是用戶id;action的值爲:“show”, “answer”, “skip”;當action是"answer"時,answer_id不爲空,相反,當action是"show"和"skip"時爲空(null);q_num是問題的數字序號。
寫一條sql語句找出回答率最高的問題。
舉例:
輸入
1 2 3 4 5 6 7 8 |
+------+-----------+--------------+------------+-----------+------------+ | 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 | +------+-----------+--------------+------------+-----------+------------+ |
輸出
1 2 3 4 5 |
+-------------+ | survey_log | +-------------+ | 285 | +-------------+ |
說明
問題285的回答率爲1/1,然而問題369的回答率是0/1,所以輸出是285。
注意: 最高回答率的意思是:同一個問題出現的次數中回答的比例。
項目十八:各部門前3高工資的員工(難度:中等)
將項目7中的employee表清空,重新插入以下數據(其實是多插入5,6兩行):
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
| 5 | Janet | 69000 | 1 |
| 6 | Randy | 85000 | 1 |
+----+-------+--------+--------------+
編寫一個 SQL 查詢,找出每個部門工資前三高的員工。例如,根據上述給定的表格,查詢結果應返回:
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| IT | Randy | 85000 |
| IT | Joe | 70000 |
| Sales | Henry | 80000 |
| Sales | Sam | 60000 |
+------------+----------+--------+
此外,請考慮實現各部門前N高工資的員工功能。
項目十九:平面上最近距離
point_2d 表包含一個平面內一些點(超過兩個)的座標值(x,y)。
寫一條查詢語句求出這些點中的最短距離並保留2位小數。
x |
y |
-1 |
-1 |
0 |
0 |
-1 |
-2 |
最短距離是1,從點(-1,-1)到點(-1,2)。所以輸出結果爲:
shortest |
1.00 |
注意: 所有點的最大距離小於10000。
項目二十:行程和用戶(難度:困難)
Trips 表中存所有出租車的行程信息。每段行程有唯一鍵 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外鍵。Status 是枚舉類型,枚舉成員爲 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。
+----+-----------+-----------+---------+--------------------+----------+
| Id | Client_Id | Driver_Id | City_Id | Status |Request_at|
+----+-----------+-----------+---------+--------------------+----------+
| 1 | 1 | 10 | 1 | completed |2013-10-01|
| 2 | 2 | 11 | 1 | cancelled_by_driver|2013-10-01|
| 3 | 3 | 12 | 6 | completed |2013-10-01|
| 4 | 4 | 13 | 6 | cancelled_by_client|2013-10-01|
| 5 | 1 | 10 | 1 | completed |2013-10-02|
| 6 | 2 | 11 | 6 | completed |2013-10-02|
| 7 | 3 | 12 | 6 | completed |2013-10-02|
| 8 | 2 | 12 | 12 | completed |2013-10-03|
| 9 | 3 | 10 | 12 | completed |2013-10-03|
| 10 | 4 | 13 | 12 | cancelled_by_driver|2013-10-03|
+----+-----------+-----------+---------+--------------------+----------+
Users 表存所有用戶。每個用戶有唯一鍵 Users_Id。Banned 表示這個用戶是否被禁止,Role 則是一個表示(‘client’, ‘driver’, ‘partner’)的枚舉類型。
+----------+--------+--------+
| Users_Id | Banned | Role |
+----------+--------+--------+
| 1 | No | client |
| 2 | Yes | client |
| 3 | No | client |
| 4 | No | client |
| 10 | No | driver |
| 11 | No | driver |
| 12 | No | driver |
| 13 | No | driver |
+----------+--------+--------+
寫一段 SQL 語句查出 2013年10月1日 至 2013年10月3日 期間非禁止用戶的取消率。基於上表,你的 SQL 語句應返回如下結果,取消率(Cancellation Rate)保留兩位小數。
+------------+-------------------+
| Day | Cancellation Rate |
+------------+-------------------+
| 2013-10-01 | 0.33 |
| 2013-10-02 | 0.00 |
| 2013-10-03 | 0.50 |
+------------+-------------------+
答案,來自官方
項目十七 查詢回答率最高的問題 (難度:中等)
根據question_id分組,然後根據回答率降序排序,並輸出第一條記錄。回答率就是action字段中’answer’的次數除以’show’的次數。要計算回答率,就需要統計action中’answer’和’show’的個數。可以根據question_id分組,然後分別統計出每道題’answer’和’show’的次數。
首先,按question_id分組,然後用SUM()和IF()統計每道題’answer’和’show’的次數:
1 2 3 4 |
SELECT question_id, SUM(IF(action='show', 1, 0)) AS num_show, SUM(IF(action='answer', 1, 0)) AS num_answer FROM survey_log GROUP BY question_id |
再按question_id分組,並根據回答率降序排序:
1 2 3 4 5 6 |
SELECT question_id AS survey_log FROM (SELECT question_id, SUM(IF(action='show', 1, 0)) AS num_show, SUM(IF(action='answer', 1, 0)) AS num_answer FROM survey_log GROUP BY question_id) AS t ORDER BY (num_answer/num_show) DESC; |
最後輸出第一條記錄:
1 2 3 4 5 6 |
SELECT question_id AS survey_log FROM (SELECT question_id, SUM(IF(action='show', 1, 0)) AS num_show, SUM(IF(action='answer', 1, 0)) AS num_answer FROM survey_log GROUP BY question_id) AS t ORDER BY (num_answer/num_show) DESC LIMIT 1; |
項目十八 各部門工資第三高的員工
思路一: 因爲只有兩個部門,我們可以取巧分別對每個部門按工資降序排名,取前三行,然後UNION。
需要注意的是,ORDER BY 和 LIMIT本身不支持在子查詢中使用。所以需要加上括號形成獨立的幾個表而不是UNION的子查詢。
思路二:也是大家普遍在網上搜到的答案。
和分數排名的思想類似,用到了輔助表。
emp1是我們的基礎表,emp2是輔助表。
將emp1裏的每個salary和整張emp2比較。下面來捋下過程。
以IT部門爲例,emp1的salary有 6.9萬,7萬,8.5萬,9萬四個數
① emp1工資是6.9萬的時候,emp2表裏的 count是3,說明有三個大於它的(間接說明它是第四大)
② emp1工資是7萬的時候,emp2表裏的count是2,說明有兩個大於它的(間接說明它是第三大)
③emp1工資是8.5萬的時候,emp2表裏的count是1,說明有1個大於它的(間接說明它是第二大)
④emp1工資是9萬的時候,emp2表裏的count是0,說明沒有大於它的(間接說明它是最大的)
在code裏就是emp2.Salary > (emp1.Salary =6.9)
然後我們要求的是前三大,所以是COUNT() < 3。
項目十九 平面上最近距離
連接(join)兩張 point_2d 表生成所有可能的點對,然後計算距離,求最小距離並保留小數點後2位。
1 2 3 |
SELECT ROUND(SQRT(MIN(POW(p1.x-p2.x,2)+POW(p1.y-p2.y,2))),2) AS shortest FROM point_2d AS p1, point_2d AS p2 WHERE p1.x <> p2.x OR p1.y <> p2.y; |
項目二十 行程和用戶
題目意思本身很簡單,難點在於如何同時計算取消的數量和總數量。
總數量很簡單,就是COUNT(*),
同時計算取消數量可以用SUM(CASE END)來實現。對status列計算數量,如果是cancel就記1,complete記爲0.
P.S. 如果需要userID 匹配 clientID和driverID兩列,需要寫兩個Lef Join。 但是可以通過CASE ...END 在最終結果只顯示一列。