問題描述
我們現在有一張表titles,共有4個字段,分別是emp_no(員工編號),title(職位),from_date(起始時間),to_date(結束時間),記錄的是員工在某個時間段內職位名稱,因為會存在升職,轉崗之類的,里面emp_no可能會對應多個職位,我們現在要取到所有員工最近的職位信息,包括離職員工。
本文介紹兩種方法去實現結果:
方法一
嵌套一個group by+max()子查詢獲取最近的職位信息。
思路
- 通過對emp_no分組取每個emp_no對應的最大的from_date;
SELECT
emp_no,
max( from_date ) AS max_date
FROM
titles
GROUP BY
emp_no
結果如下:
- 通過查詢出來的最大的from_date取篩選最近的的一條職位信息。
SELECT
t.emp_no,
t.title
FROM
titles t
LEFT JOIN ( SELECT emp_no, max( from_date ) AS max_date FROM titles GROUP BY emp_no ) et
ON t.emp_no = et.emp_no AND t.from_date = et.max_date
結果如下:
方法二
通過rank over partition by函數實現,這個目前是Oracle獨有的函數,如果你用的是mysql或者sql server就沒辦法使用了。
語法
功能:在原有表的基礎上加上一個根據條件排序的偽列。
SELECT
*,
RANK() OVER (PARTITION BY emp_no ORDER BY from_date DESC) AS rank
FROM
titles
RANK() OVER (PARTITION BY emp_no ORDER BY from_date DESC) AS rank
表示把表根據emp_no進行分區,然后在分區內根據from_date進行降序排列,排序結果生成一列命名為rank。
我們之前在問題里面提到了一個emp_no會對應多條職位信息,然后對於每個emp_no的記錄進行一個降序排列,接下來我們只需要把上面的結果當成一個子查詢然后篩選rank = 1
就好了。
完整代碼如下
SELECT
*
FROM
( SELECT *, RANK ( ) OVER ( PARTITION BY emp_no ORDER BY from_date DESC ) AS rank FROM titles ) r
WHERE
r.rank = '1'
由於我筆記本只裝了mysql的環境,所以就沒法給各位展示效果了。
綜上,如果各位目前使用的是Oracle,推薦各位使用方法二:
- 方法二容錯率高,如果titles表里面有兩條記錄emp_no和from_date都是一樣的,方法一就會報錯了,單條子查詢返回多行;
- 方法二還可以實現取第二條,第三條等等的記錄,方法一只有一個最大或者最小可供選擇。
peace~