以下內容首發於我的個人博客網站:
http://riun.xyz
來自一位朋友最近做的攜程筆試題,其中有一道關於SQL的題目是這樣的:
一、題目
Mysql數據庫中有如下兩張表,app表爲應用表,儲存的是應用相關信息;alert表爲預警表,儲存的是各應用在一段時間內的預警信息。
app:
app_id | app_name |
---|---|
1001 | 應用1 |
1002 | 應用2 |
… | … |
alert:
alert_id | app_id | alert_info | alert_date |
---|---|---|---|
324324 | 1001 | 預警信息1 | 2020-02-01 12:30:23 |
342343 | 1002 | 預警信息2 | 2020-02-01 12:31:23 |
… | … | … | … |
請寫出查詢出前7天內預警數是Top3的應用名稱及其預警數,並按預警數由大到小排序。
原題目圖片:
給出的兩表數據是這樣的:
給出的最終查詢結果是這樣的:
app_id | app_name | alert_count |
---|---|---|
1001 | application1 | 4 |
1005 | application5 | 3 |
1002 | application2 | 2 |
二、我的理解
最初審視這道題目的時候,讀到**”查詢出前7天內預警數是Top3”,我的想法是從最早的時間開始,向後算7天內的數據**。即,若今天是4.1號,最早的時間就是3.22號,那麼前7天內的數據應該是在3.22~3.28之間的數據。我們暫且把這個叫做思路1。
按照思路1,我開始寫sql,但最終因爲無法想出【從最早的時間開始,向後數7天】這個限制條件到底應該怎樣寫而以失敗告終。所以只寫了一個不包含此條件的sql。
我的sql是:
select app.app_id, app.app_name, res.count alert_count
from app RIGHT JOIN
(select app_id, count(*) count from alert GROUP BY app_id order by count desc LIMIT 3) res
on app.app_id = res.app_id
如果知道這個條件怎樣寫,那麼向裏面添加 where 時間限制條件
即可。
即,最終的sql應該是:
select app.app_id, app.app_name, res.count alert_count
from app RIGHT JOIN
(select app_id, count(*) count from alert where 時間限制條件 GROUP BY app_id order by count desc LIMIT 3) res
on app.app_id = res.app_id
暫且先不說這個時間限制條件,也不說這個sql是否符合題意要求,來說說我的思路吧。
題目:【查詢出前7天內預警數是Top3的應用名稱及其預警數,並按預警數由大到小排序】,我的思路是如下展開的:
1、由於在alert
表中每條同一臺應用的預警信息都有相同的app_id
,那麼我首先想到了要在alert
表裏對app_id
進行分組,分組後查出各組的數量,就得到了應用與預警數的對照表。那麼sql就是:
select app_id, count(*) from alert GROUP BY app_id
(上述將count(*)
換成count(qpp_id)
是相同的)
查詢結果:
2、然後將其按照預警數倒序排序並只拿出top3。sql就是:
select app_id, count(*) count from alert GROUP BY app_id ORDER BY count desc LIMIT 3
查詢結果:
這樣只需要再拿到app_name
即可。app_name
在app
表裏,那麼將查詢結果作爲一個新表與app
表做連接查詢即可查詢出結果。sql是:
select app.app_id, app.app_name, res.count alert_count
from app RIGHT JOIN
(select app_id, count(*) count from alert GROUP BY app_id order by count desc LIMIT 3) res
on app.app_id = res.app_id
查詢結果:
這樣看來好像添加上 where 時間限制條件
這道題目就解決了。可是後來我又重新審視了一遍題目,發現了一些問題…
三、另一個選擇
當我再次審視這道題時,我將數據仔仔細細的對照了一遍。如果按照我的思路1,即,題目中的【查詢出前7天內預警數是Top3】這樣理解:“若今天是4.1號,最早的時間就是3.22號,那麼前7天內的數據應該是在3.22~3.28之間的數據“。仔細觀察給出的數據,如果這樣算,所有數據都被包含進去了,並沒有任何一個數據因爲【前7天內】這個限制條件而被刷掉,那麼給出的查詢限制條件就沒有了意義。那麼幹嘛還要這個多餘的限制條件呢?爲了迷惑作答者的思路?爲了讓作答者寫這個”比較難寫而對本題無意義的“的時間限制條件嗎?
我覺得不是。
於是我就嘗試着換了一個我並不贊同的方式思考。假設題目中【查詢出前7天內預警數是Top3】是另一個意思:以目前爲時間點,向前數7天。比如今天是4.1,那麼前7天內的數據應該是在3.26~4.1之間的數據。 再回頭看數據, 這樣算來就存在3.22號和3.24號這兩天的數據被刷掉,那麼這個限制條件便有了意義。我們把這個叫做思路2。
現在我們不寫sql語句,我口述下數據情況(順序不代表插入順序)來判斷此思路是否正確:
- 3.22號1003機器預警
- 3.14號1002機器預警
- 3.26號:
- 1001機器預警,共4次
- 1002機器預警,共2次
- 1003機器預警,共1次
- 1004機器預警,共1次
- 1005機器預警,共3次
以上是給出的數據所表達出來的是實際情況。而題目**“請寫出查詢出前7天內預警數是Top3的應用名稱及其預警數,並按預警數由大到小排序。”** 所給出的結果是:
top3分別是:
- 1001,4次預警
- 1005,3次預警
- 1002,2次預警
就說明了題目是按照思路2來的。
如果按照思路1來,沒有數據被刷掉,使用了全部數據,那麼結果應該是:
top3分別是:
- 1001,4次預警
- 1002、1005,均3次預警
- 1003,2次預警
顯然並不符合給出的結果。
好了,這個烏龍被發現後,我再次看我按照思路1寫的sql:就算我們找到了那個符合思路1的正確的where 時間限制
條件,添加進去我們的sql仍然不對,因爲題目她並不是這個意思啊 …( _ _)ノ|。 不知道這個算不算是出題者的一個失誤:按照題目的意思明顯是思路1,但是給出的結果卻是參照思路2的。
除此之外我的sql還有一個錯誤,按照思路1來top3包含了4條數據,有一個同排名的數據。而我並沒有查出4條數據,且至今仍不知道如何將這個相同排名的全部查出來…
【相同排名全部查詢】先告一段落,我們來看這道題。現在知道了她是按照思路2走,就好辦了,以當前時間點爲參照,查詢出前7天內的數據的限制語句是:
where DATE_SUB(CURDATE(), INTERVAL 6 DAY) <= date(時間字段)
我們將此字段添加到我的sql中:
select app.app_id, app.app_name, res.count alert_count
from app RIGHT JOIN
(select app_id, count(*) count from alert where DATE_SUB(CURDATE(), INTERVAL 6 DAY) <=
date(alert_date) GROUP BY app_id order by count desc LIMIT 3) res
on app.app_id = res.app_id
查詢結果:
和所要求的查詢結果一致。sql正確。(不過我的查詢仍不適用於存在相同排名的情況下,只適用本道題目)
希望你看的開心(●’◡’●)