Leetcode SQL(一)

目錄

613. 直線上的最近距離🔒

182. 查找重複的電子郵箱

627. 交換工資

584. 尋找用戶推薦人🔒

1082. 銷售分析 I🔒

577. 員工獎金🔒

1327. 列出指定時間段內所有的下單產品🔒

603. 連續空餘座位 🔒

1407. 排名靠前的旅行者🔒

1211. 查詢結果的質量和佔比🔒


613. 直線上的最近距離🔒

https://leetcode-cn.com/problems/shortest-distance-in-a-line/

表 point 保存了一些點在 x 軸上的座標,這些座標都是整數。

寫一個查詢語句,找到這些點中最近兩個點之間的距離。

| x   |
|-----|
| -1  |
| 0   |
| 2   |

最近距離顯然是 '1' ,是點 '-1' 和 '0' 之間的距離。所以輸出應該如下:

| shortest|
|---------|
| 1       |

注意:每個點都與其他點座標不同,表 table 不會有重複座標出現。

題解

一:我們知道最近的距離,必定是排序後的相鄰元素差值的絕對值的最小值。那麼🏁是如何將每一行的數據與下一行的數據進行對比。在使用 row_number() over()函數時候,over()裏頭的分組以及排序的執行晚於 where 、group by、  order by 的執行。先生成兩張臨時表a和b,均是在原表的前面添加一個id字段,a的id從1開始,b的id從2開始。

select min(abs(a.x - b.x)) shortest from
(select ROW_NUMBER() over(order by x) as id, x from point)a
left join 
(select ROW_NUMBER() over(order by x) + 1 as id, x from point)b
on a.id = b.id
where b.x is not null

二:可以考慮將x中的值兩兩組合(當然不能和自己組合),這種可以用笛卡爾積來做。這種有一個缺點,我們必須排除與自身的組合,因爲不然最小值肯定是0,但是若排出和自身值相等的組合,在有重複座標,會出錯,此時最小值應該是0,但這樣做結果必然大於0。不過該題有給出注意事項,就是不會出現重複座標,故而不會出現上述情況。

select min(abs(a.x - b.x)) shortest
from 
point a 
left join 
point b
on a.x < b.x

 

182. 查找重複的電子郵箱

https://leetcode-cn.com/problems/duplicate-emails/

編寫一個 SQL 查詢,查找 Person 表中所有重複的電子郵箱。

示例:

根據以上輸入,你的查詢應返回以下結果:


說明:所有電子郵箱都是小寫字母。

題解

一:group by 分組以及聚合函數的使用。當技術大於1的時候說明是重複的。

select Email from Person group by Email having count(Email) > 1

627. 交換工資

https://leetcode-cn.com/problems/swap-salary/

給定一個 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交換所有的 f 和 m 值(例如,將所有 f 值更改爲 m,反之亦然)。要求只使用一個更新(Update)語句,並且沒有中間的臨時表。

注意,您必只能寫一個 Update 語句,請不要編寫任何 Select 語句。

例如:

運行你所編寫的更新語句之後,將會得到以下表:

題解

一:case when then else的使用。如何將字段的值按條件重新賦值。

Update salary set sex = (case when sex = "f" then "m" else "f" end)

584. 尋找用戶推薦人🔒

https://leetcode-cn.com/problems/find-customer-referee/

給定表 customer ,裏面保存了所有客戶信息和他們的推薦人。

寫一個查詢語句,返回一個編號列表,列表中編號的推薦人的編號都 不是 2。對於上面的示例數據,結果爲:

題解

一:注意null的特殊處理。下面轉自官方題解,https://leetcode-cn.com/problems/find-customer-referee/solution/xun-zhao-yong-hu-tui-jian-ren-by-leetcode/。MySQL 使用三值邏輯 —— TRUE, FALSE 和 UNKNOWN。任何與 NULL 值進行的比較都會與第三種值 UNKNOWN 做比較。這個“任何值”包括 NULL 本身!這就是爲什麼 MySQL 提供 IS NULL 和 IS NOT NULL 兩種操作來對 NULL 特殊判斷。因此,在 WHERE 語句中我們需要做一個額外的條件判斷 `referee_id IS NULL'。

select name
from customer
where referee_id != 2 or referee_id is null

下面的解法同樣是錯誤的,錯誤原因同上。避免錯誤的祕訣在於使用 IS NULL 或者 IS NOT NULL 兩種操作來對 NULL 值做特殊判斷。

SELECT name FROM customer WHERE referee_id = NULL OR referee_id <> 2;

1082. 銷售分析 I🔒

https://leetcode-cn.com/problems/sales-analysis-i/

題解

一:兩張表join, 其中第二張表c拿到最大的銷售總金額(b表,拿到每個銷售的銷售總金額),a表同b表,都是拿到每個銷售的銷售總金額,用金額join,條件銷售總金額等於最大銷售總金額。

select seller_id from
(select seller_id, sum(price) sum_price
from Sales
group by seller_id
)a
left join 
(select max(sum_price) max_price from 
(select seller_id, sum(price) sum_price
from Sales
group by seller_id
)b)c
on sum_price = max_price
where sum_price = max_price

分步驟:拿到每個銷售的銷售總金額

select seller_id, sum(price) sum_price
from Sales
group by seller_id

 在拿到每個銷售的銷售總金額後,拿到最高的銷售金額。

select max(sum_price) max_price from 
(select seller_id, sum(price) sum_price
from Sales
group by seller_id
)b

二:all的使用,max和all函數起到的作用是一樣的, all和每一個進行比較(大於最大的或者小於最小的),any 則是大於任何一個都可以(大於最小的,小於最大的)

select seller_id from
Sales 
group by 
seller_id
having sum(price) >=
all(select sum(price) sum_price from Sales group by seller_id)

577. 員工獎金🔒

https://leetcode-cn.com/problems/employee-bonus/

題解

一:注意null值

select name, bonus
from Employee e left join Bonus b
on e.empId = b.empId
where b.empId is null or bonus < 1000

1327. 列出指定時間段內所有的下單產品🔒

https://leetcode-cn.com/problems/list-the-products-ordered-in-a-period/

寫一個 SQL 語句,要求獲取在 2020 年 2 月份下單的數量不少於 100 的產品的名字和數目。返回結果表單的順序無要求。查詢結果的格式如下:

題解

一:日期函數:提取月份month,提取年份year。

select product_name, sum(unit) unit
from 
(
select  o.product_id, product_name, unit
from Orders o left join Products p
on o.product_id = p.product_id
where month(order_date) = 2 and year(order_date) = 2020
)a
group by product_id, product_name
having sum(unit) >= 100

二:當作字符串處理,like,

where order_date like "2020-02%"
select product_name, sum(unit) unit
from 
(
select  o.product_id, product_name, unit
from Orders o left join Products p
on o.product_id = p.product_id
where order_date like "2020-02%"
)a
group by product_id, product_name
having sum(unit) >= 100

603. 連續空餘座位 🔒

https://leetcode-cn.com/problems/consecutive-available-seats/

幾個朋友來到電影院的售票處,準備預約連續空餘座位。你能利用表 cinema ,幫他們寫一個查詢語句,獲取所有空餘座位,並將它們按照 seat_id 排序後返回嗎?

對於如上樣例,你的查詢語句應該返回如下結果。

注意:seat_id 字段是一個自增的整數,free 字段是布爾類型('1' 表示空餘, '0' 表示已被佔據)。連續空餘座位的定義是大於等於 2 個連續空餘的座位。

題解

錯解:left join會存在一個情況,只要左側非空,右側即使爲空,也會返回結果,這帶來一個不方便的例如值返回一條記錄的,按理來說這不是所要求的解,但是卻不好淘汰。例如只有一個座位且是空座位,符合and的第一個條件,以及第二個條件or後面的條件。還有當最後一張💺空閒,且前面均不空,這個座位也會被返回。

select a.seat_id
from cinema a
left join cinema b
on a.seat_id + 1 = b.seat_id
where a.free = 1 and (b.free = 1 or b.free is null)

一:之前習慣了left join,left join會存在一個情況,只要左側非空,右側即使爲空,也會返回結果,這帶來一個不方便的例如值返回一條記錄的,按理來說這不是所要求的解,但是卻不好淘汰。join兩邊均非空纔會出現,這邊沒像錯解用a.seat_id + 1 = b.seat_id,這樣會出現兩次,故用distinct。

seat_id free seat_id free
4 1 3 1
3 1 4 1
5 1 4 1
4 1 5 1
select distinct a.seat_id
from cinema a join cinema b
  on abs(a.seat_id - b.seat_id) = 1
  and a.free = true and b.free = true
order by a.seat_id

1407. 排名靠前的旅行者🔒

https://leetcode-cn.com/problems/top-travellers/

id 是該表單主鍵。user_id 是本次行程的用戶的 id, 而該用戶此次行程距離爲 distance。寫一段 SQL , 報告每個用戶的旅行距離。返回的結果表單,  以 travelled_distance 降序排列, 如果有兩個或者更多的用戶旅行了相同的距離, 那麼再以 name 升序排列。查詢結果格式, 如下例所示。

Elvis 和 Lee 旅行了 450 英里, Elvis 是排名靠前的旅行者, 因爲他的名字在字母表上的排序比 Lee 更小。Bob, Jonathan, Alex 和 Alice 只有一次行程, 我們只按此次行程的全部距離對他們排序。Donald 沒有任何行程, 他的旅行距離爲 0。

題解

一:case when then來進行判斷,也可以處理給空值賦默認值的問題。

select name, case 
when r.user_id is null then 0
else sum(distance) end travelled_distance
from Users u
left join Rides r 
on u.id = r.user_id
group by u.id 
order by travelled_distance desc, name asc

二:ifnull來處理空值,當第一個參數爲null,取第二個參數的值

select name, ifnull(sum(distance), 0) travelled_distance
from Users u
left join Rides r 
on u.id = r.user_id
group by u.id 
order by travelled_distance desc, name asc

1211. 查詢結果的質量和佔比🔒

https://leetcode-cn.com/problems/queries-quality-and-percentage/

此表沒有主鍵,並可能有重複的行。此表包含了一些從數據庫中收集的查詢信息。“位置”(position)列的值爲 1 到 500 。“評分”(rating)列的值爲 1 到 5 。評分小於 3 的查詢被定義爲質量很差的查詢。

題解

一:純粹的sql函數

select query_name, round(sum(rating / position) / count(rating), 2) quality, 
round(sum(rating < 3) / count(rating) * 100, 2) poor_query_percentage
from Queries
group by query_name

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章