當計算欄位邂逅子查詢
來自專欄 數據分析師成長之路
我們平常用的計算欄位可能大多是 col1/col2,col1*col2,col1*10-col2 這種「小學」式的計算欄位,用子查詢來做計算欄位的還比較少見,今天給大家分享兩個例子,來一起學習一下。
例1:
假如有兩個表,一個是customers表,裡面有顧客的姓名,顧客所在地等個人信息,另一個是orders表,裡面記錄了訂單號,下單的顧客編號等信息,需要注意的是,有的顧客可能下過多個訂單,而有的可能一個都沒下(比如你女朋友過生日,你在某貓的Olay旗艦店給她買了兩支小白瓶,過了段時間情人節,又在SK-II旗艦店給買了一瓶神仙水,我呢比較窮,只註冊了賬號,什麼都沒買)。
那麼問題來了,我怎麼統計每個顧客下了多少訂單呢?一天好多個訂單的,除了土豪,是不是還有可能是刷單黨?
如果只看單個顧客,我們可以用下面的語句來查詢:
SELECT COUNT(*) AS ord_num
FROM orders
WHERE cust_name = iRunning ;
要對每個顧客執行COUNT(*) ,應該將它作為一個子查詢:
SELECT cust_name, cust_state
(SELECT COUNT(*)
FROM orders
WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers
ORDER BY cust_name;
orders 是一個計算欄位,它是由圓括弧中的子查詢建立的。該子查詢對檢索出的每個顧客執行一次。
可能你注意到上面的子查詢語句和我們平時見的查詢不太一樣,我們平時見的類似的查詢大多是像下面這種:
SELECT col_a, col_b
FROM table_a, table_b
WHERE table_a.col_c= table_b.col_c
而上述的整體模式是:
SELECT col_a,
(SELECT COUNT(*)
FROM table_b
WHERE table_b.col_c = table_a.col_c) AS col_calc
FROM table_a;
例2:分數排名
編寫一個SQL查詢來實現分數排名。如果兩個分數相同,則兩個分數排名(Rank)相同。請注意,平分後的下一個名次應該是下一個連續的整數值。換句話說,名次之間不應該有「間隔」。
思路:假如每個人分數不一樣,那麼一個人的名次就是大於等於他分數的數量,例如4個人,大於等於最後一名的分數有四個,所以他是第4名。
假如有人分數一樣,比如3個人,兩個一樣,另一個比這兩個高,高的顯然是第一名,因為大於等於他分數的就一個,但是對於兩個分數一樣的,大於等於他們分數的數有3個,顯然不能是第三名,但大於等於他們分數的不同分數只有兩個,正好是第二名。
對上例中的組合進行遍歷,score_unique代表大於等於score的不同分數:
對score_unique進行計數後正好對應分數的名次。
我們用兩種寫法實現,一種是聯結表:
SELECT t1.Score as Score, COUNT(t2.Score) as Rank
FROM Scores t1
LEFT JOIN (SELECT DISTINCT Score FROM Scores) t2
ON t1.Score <= t2.Score
GROUP BY t1.id
ORDER BY t1.Score DESC;
另一種是用子查詢做計算欄位,對每個分數都計算大於等於它的不同分數的數量:
SELECT Score,
(SELECT COUNT(DISTINCT Score)
FROM Scores
WHERE Score >= t1.Score) rank
FROM Scores t1
ORDER BY Score DESC;
經過這兩個例子,相信對子查詢做計算欄位有一認識了。
參考資料:
《SQL必知必會》
http://leetcode.com
推薦閱讀:
※memcached plugin(handlersocket),Memcached的一點看法
※MySQL成數據勒索新目標,開發4步自查
※為什麼推薦使用MySQLi?
※想非常精通資料庫的話需要哪方面數學?
※說說 MySQL JSON 數據類型