leetcode sql 經(jīng)典70題總結(jié)一(排名的使用)

image.png

一、通過排名或者范圍條件連表篩選特殊行

  • 第一行
  • 最后一行
  • 區(qū)間(第一行到第二行或者連續(xù)區(qū)間)
  • 找中位數(shù)
  • 通過排名進行分組或者連續(xù)區(qū)間
1.使用條件篩選連表找區(qū)間

Employee 表保存了一年內(nèi)的薪水信息。

請你編寫 SQL 語句,來查詢每個員工每個月最近三個月的累計薪水(不包括當前統(tǒng)計月,不足三個月也要計算)。

結(jié)果請按 'Id' 升序,然后按 'Month' 降序顯示。

示例:
輸入:

Id Month Salary
1 1 20
2 1 20
1 2 30
2 2 30
3 2 40
1 3 40
3 3 60
1 4 60
3 4 70

輸出:

Id Month Salary
1 3 90
1 2 50
1 1 20
2 1 20
3 3 100
3 2 40

解釋:

員工 '1' 除去最近一個月(月份 '4'),有三個月的薪水記錄:月份 '3' 薪水為 40,月份 '2' 薪水為 30,月份 '1' 薪水為 20。

所以近 3 個月的薪水累計分別為 (40 + 30 + 20) = 90,(30 + 20) = 50 和 20。

Id Month Salary
1 3 90
1 2 50
1 1 20

員工 '2' 除去最近的一個月(月份 '2')的話,只有月份 '1' 這一個月的薪水記錄。

Id Month Salary
2 1 20

員工 '3' 除去最近一個月(月份 '4')后有兩個月,分別為:月份 '4' 薪水為 60 和 月份 '2' 薪水為 40。所以各月的累計情況如下:

Id Month Salary
3 3 100
3 2 40

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/find-cumulative-salary-of-an-employee
著作權(quán)歸領扣網(wǎng)絡所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

代碼中使用一個范圍連表,在使用最小月份去重最后一個月

# Write your MySQL query statement below
select d1.Id,d1.Month,d1.Salary
from

  (select a.Id,a.Month,sum(b.Salary) Salary
  from Employee a 
  left join Employee  b
  on a.Id = b.Id and a.month >= b.month and b.month >=a.month-2
  group by a.Id,a.Month
  ) d1

left join

  (select c.Id,Max(c.Month) maxMonth
  from Employee c
  group by c.Id) d2

on d1.id = d2.id
where d1.Month < d2.maxMonth
order by d1.id asc,d1.Month desc
2.使用排名來找中位數(shù)

Employee 表包含所有員工。Employee 表有三列:員工Id,公司名和薪水。

+-----+------------+--------+
|Id | Company | Salary |
+-----+------------+--------+
|1 | A | 2341 |
|2 | A | 341 |
|3 | A | 15 |
|4 | A | 15314 |
|5 | A | 451 |
|6 | A | 513 |
|7 | B | 15 |
|8 | B | 13 |
|9 | B | 1154 |
|10 | B | 1345 |
|11 | B | 1221 |
|12 | B | 234 |
|13 | C | 2345 |
|14 | C | 2645 |
|15 | C | 2645 |
|16 | C | 2652 |
|17 | C | 65 |
+-----+------------+--------+
請編寫SQL查詢來查找每個公司的薪水中位數(shù)。挑戰(zhàn)點:你是否可以在不使用任何內(nèi)置的SQL函數(shù)的情況下解決此問題。

+-----+------------+--------+
|Id | Company | Salary |
+-----+------------+--------+
|5 | A | 451 |
|6 | A | 513 |
|12 | B | 234 |
|9 | B | 1154 |
|14 | C | 2645 |
+-----+------------+--------+

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/median-employee-salary
著作權(quán)歸領扣網(wǎng)絡所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

下面先進行排名,然后使用in()進行偶數(shù)個數(shù)組的中位數(shù)和奇數(shù)個數(shù)組的中位數(shù)

# Write your MySQL query statement below
select c1.id,c1.company,c1.salary
from 
  (select a.id,a.Company,a.salary,
  case @cp when a.Company then @rk:=@rk+1 else @rk:=1 end rk,
  @cp:=a.Company
  from Employee a,(select @rk:=0,@cp:='') b
  order by a.Company,a.salary) c1
left join
  (select company,count(1)/2 p
  from Employee
  group by company ) c2
on c1.company=c2.company
where c1.rk in (c2.p+0.5,c2.p+1,c2.p)
3.使用排名找特定的某一行

表: Users

+----------------+---------+
| Column Name | Type |
+----------------+---------+
| user_id | int |
| join_date | date |
| favorite_brand | varchar |
+----------------+---------+
user_id 是該表的主鍵
表中包含一位在線購物網(wǎng)站用戶的個人信息,用戶可以在該網(wǎng)站出售和購買商品。
表: Orders

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| order_id | int |
| order_date | date |
| item_id | int |
| buyer_id | int |
| seller_id | int |
+---------------+---------+
order_id 是該表的主鍵
item_id 是 Items 表的外鍵
buyer_id 和 seller_id 是 Users 表的外鍵
表: Items

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| item_id | int |
| item_brand | varchar |
+---------------+---------+
item_id 是該表的主鍵

寫一個 SQL 查詢確定每一個用戶按日期順序賣出的第二件商品的品牌是否是他們最喜愛的品牌。如果一個用戶賣出少于兩件商品,查詢的結(jié)果是 no 。

題目保證沒有一個用戶在一天中賣出超過一件商品

下面是查詢結(jié)果格式的例子:

Users table:
+---------+------------+----------------+
| user_id | join_date | favorite_brand |
+---------+------------+----------------+
| 1 | 2019-01-01 | Lenovo |
| 2 | 2019-02-09 | Samsung |
| 3 | 2019-01-19 | LG |
| 4 | 2019-05-21 | HP |
+---------+------------+----------------+

Orders table:
+----------+------------+---------+----------+-----------+
| order_id | order_date | item_id | buyer_id | seller_id |
+----------+------------+---------+----------+-----------+
| 1 | 2019-08-01 | 4 | 1 | 2 |
| 2 | 2019-08-02 | 2 | 1 | 3 |
| 3 | 2019-08-03 | 3 | 2 | 3 |
| 4 | 2019-08-04 | 1 | 4 | 2 |
| 5 | 2019-08-04 | 1 | 3 | 4 |
| 6 | 2019-08-05 | 2 | 2 | 4 |
+----------+------------+---------+----------+-----------+

Items table:
+---------+------------+
| item_id | item_brand |
+---------+------------+
| 1 | Samsung |
| 2 | Lenovo |
| 3 | LG |
| 4 | HP |
+---------+------------+

Result table:
+-----------+--------------------+
| seller_id | 2nd_item_fav_brand |
+-----------+--------------------+
| 1 | no |
| 2 | yes |
| 3 | yes |
| 4 | no |
+-----------+--------------------+

id 為 1 的用戶的查詢結(jié)果是 no,因為他什么也沒有賣出
id為 2 和 3 的用戶的查詢結(jié)果是 yes,因為他們賣出的第二件商品的品牌是他們自己最喜愛的品牌
id為 4 的用戶的查詢結(jié)果是 no,因為他賣出的第二件商品的品牌不是他最喜愛的品牌

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/market-analysis-ii
著作權(quán)歸領扣網(wǎng)絡所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

代碼中先進行排序,直接使用序號進行過濾

# Write your MySQL query statement below
select u.user_id seller_id,if(i.item_brand=u.favorite_brand,'yes','no') 2nd_item_fav_brand
from Users u  left join
   (select d.seller_id,d.order_date,d.rank
   from
       (select c.seller_id,c.order_date,case when @seller=c.seller_id then @rk:=@rk+1 else @rk:=1 end rank,   @seller:=c.seller_id temp
       from
          (select * from Orders order by seller_id,order_date) c,(select @seller:=-1,@rk:=-1) b
       ) d 
   where d.rank =2) o 
on u.user_id = o.seller_id
left join Orders t on o.seller_id = t.seller_id and o.order_date = t.order_date
left join Items i on t.item_id = i.item_id
order by u.user_id

二、通過排名進行分組或者連續(xù)區(qū)間

為什么要使用這種方式分組,因為有時候你的分組維度是不存在的,你必須自己制造這個維度!比如如下這題:

Table: Failed

+--------------+---------+
| Column Name | Type |
+--------------+---------+
| fail_date | date |
+--------------+---------+
該表主鍵為 fail_date。
該表包含失敗任務的天數(shù).
Table: Succeeded

+--------------+---------+
| Column Name | Type |
+--------------+---------+
| success_date | date |
+--------------+---------+
該表主鍵為 success_date。
該表包含成功任務的天數(shù).

系統(tǒng) 每天 運行一個任務。每個任務都獨立于先前的任務。任務的狀態(tài)可以是失敗或是成功。

編寫一個 SQL 查詢 2019-01-01 到 2019-12-31 期間任務連續(xù)同狀態(tài) period_state 的起止日期(start_date 和 end_date)。即如果任務失敗了,就是失敗狀態(tài)的起止日期,如果任務成功了,就是成功狀態(tài)的起止日期。

最后結(jié)果按照起始日期 start_date 排序

查詢結(jié)果樣例如下所示:

Failed table:
+-------------------+
| fail_date |
+-------------------+
| 2018-12-28 |
| 2018-12-29 |
| 2019-01-04 |
| 2019-01-05 |
+-------------------+

Succeeded table:
+-------------------+
| success_date |
+-------------------+
| 2018-12-30 |
| 2018-12-31 |
| 2019-01-01 |
| 2019-01-02 |
| 2019-01-03 |
| 2019-01-06 |
+-------------------+

Result table:
+--------------+--------------+--------------+
| period_state | start_date | end_date |
+--------------+--------------+--------------+
| succeeded | 2019-01-01 | 2019-01-03 |
| failed | 2019-01-04 | 2019-01-05 |
| succeeded | 2019-01-06 | 2019-01-06 |
+--------------+--------------+--------------+

結(jié)果忽略了 2018 年的記錄,因為我們只關(guān)心從 2019-01-01 到 2019-12-31 的記錄
從 2019-01-01 到 2019-01-03 所有任務成功,系統(tǒng)狀態(tài)為 "succeeded"。
從 2019-01-04 到 2019-01-05 所有任務失敗,系統(tǒng)狀態(tài)為 "failed"。
從 2019-01-06 到 2019-01-06 所有任務成功,系統(tǒng)狀態(tài)為 "succeeded"。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/report-contiguous-dates
著作權(quán)歸領扣網(wǎng)絡所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

代碼中使用一個排名的序號和最小值得差值,進行分組!只要是連續(xù)的區(qū)間的,這個差值一定是相同
/* Write your PL/SQL query statement below */
SELECT *
FROM (
    SELECT 'failed' AS period_state, to_char(MIN(fail_date), 'yyyy-MM-dd') AS start_date
        , to_char(MAX(fail_date), 'yyyy-MM-dd') AS end_date
    FROM (
        SELECT a.fail_date, fail_date - minDate - rn AS groupId
        FROM (
            SELECT a.fail_date, rownum AS rn, MIN(fail_date) OVER (ORDER BY fail_date) AS minDate
            FROM Failed a
            WHERE a.fail_date >= '2019-01-01'
                AND a.fail_date <= '2019-12-31'
        ) a
    ) a
    GROUP BY a.groupId
    UNION ALL
    SELECT 'succeeded' AS period_state, to_char(MIN(success_date), 'yyyy-MM-dd') AS start_date
        , to_char(MAX(success_date), 'yyyy-MM-dd') AS end_date
    FROM (
        SELECT a.success_date, success_date - minDate - rn AS groupId
        FROM (
            SELECT a.success_date, rownum AS rn, MIN(success_date) OVER (ORDER BY success_date) AS minDate
            FROM Succeeded a
            WHERE a.success_date >= '2019-01-01'
                AND a.success_date <= '2019-12-31'
        ) a
    ) a
    GROUP BY a.groupId
) a
ORDER BY a.start_date
找連續(xù)區(qū)間

表:Logs

+---------------+---------+
| Column Name | Type |
+---------------+---------+
| log_id | int |
+---------------+---------+
id 是上表的主鍵。
上表的每一行包含日志表中的一個 ID。

后來一些 ID 從 Logs 表中刪除。編寫一個 SQL 查詢得到 Logs 表中的連續(xù)區(qū)間的開始數(shù)字和結(jié)束數(shù)字。

將查詢表按照 start_id 排序。

查詢結(jié)果格式如下面的例子:

Logs 表:
+------------+
| log_id |
+------------+
| 1 |
| 2 |
| 3 |
| 7 |
| 8 |
| 10 |
+------------+

結(jié)果表:
+------------+--------------+
| start_id | end_id |
+------------+--------------+
| 1 | 3 |
| 7 | 8 |
| 10 | 10 |
+------------+--------------+
結(jié)果表應包含 Logs 表中的所有區(qū)間。
從 1 到 3 在表中。
從 4 到 6 不在表中。
從 7 到 8 在表中。
9 不在表中。
10 在表中。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/find-the-start-and-end-number-of-continuous-ranges
著作權(quán)歸領扣網(wǎng)絡所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

# Write your MySQL query statement below
select Min(b.log_id) start_id,Max(b.log_id) end_id       
from 
(select l.log_id,if(@last_vaule=-1 or l.log_id-@last_vaule<>1,@group_id:=@group_id+1,@group_id) group_id,@last_vaule:=l.log_id
from Logs l,(select @last_vaule:=-1,@group_id:=0) a) b 
group by b.group_id
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內(nèi)容