FIRST_VALUE() 與 LAST_VALUE() 函數
FIRST_VALUE() 和 LAST_VALUE() 是窗口函數中的位移函數,用來取得窗口範圍內「第一列」或「最後一列」的值。
- FIRST_VALUE(): 取得窗口中第一列的值
- LAST_VALUE(): 取得窗口中最後一列的值
FIRST_VALUE 語法
FIRST_VALUE(column) OVER (
[PARTITION BY column_name(s)]
ORDER BY column_name(s)
[frame_clause]
)
LAST_VALUE 語法
LAST_VALUE(column) OVER (
[PARTITION BY column_name(s)]
ORDER BY column_name(s)
[frame_clause]
)
FIRST_VALUE 基本用法 (Example)
假設我們有一個 employees 資料表:
| Dept | Name | Salary |
|---|---|---|
| 業務 | 張一 | 55000 |
| 業務 | 王二 | 50000 |
| 研發 | 李三 | 70000 |
| 研發 | 趙四 | 60000 |
取得各部門薪資最高者的姓名:
SELECT
Dept,
Name,
Salary,
FIRST_VALUE(Name) OVER (PARTITION BY Dept ORDER BY Salary DESC) AS top_earner
FROM employees;
查詢結果:
| Dept | Name | Salary | top_earner |
|---|---|---|---|
| 業務 | 張一 | 55000 | 張一 |
| 業務 | 王二 | 50000 | 張一 |
| 研發 | 李三 | 70000 | 李三 |
| 研發 | 趙四 | 60000 | 李三 |
每一列都會顯示該部門薪資最高者的姓名。
LAST_VALUE 注意事項
LAST_VALUE() 有一個重要的陷阱:預設的窗口框架是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,這意味著「最後一列」實際上是「當前列」。
-- 這樣寫可能得不到預期結果
SELECT
Name,
Salary,
LAST_VALUE(Name) OVER (ORDER BY Salary DESC) AS lowest_earner
FROM employees;
要取得真正的最後一列,需要明確指定窗口框架:
SELECT
Name,
Salary,
LAST_VALUE(Name) OVER (
ORDER BY Salary DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS lowest_earner
FROM employees;
窗口框架說明
| 框架 | 說明 |
|---|---|
| UNBOUNDED PRECEDING | 從分區的第一列開始 |
| CURRENT ROW | 當前列 |
| UNBOUNDED FOLLOWING | 到分區的最後一列 |
實務應用:與最高/最低值比較
計算每位員工薪資與部門最高薪資的差距:
SELECT
Dept,
Name,
Salary,
FIRST_VALUE(Salary) OVER (PARTITION BY Dept ORDER BY Salary DESC) AS max_salary,
Salary - FIRST_VALUE(Salary) OVER (PARTITION BY Dept ORDER BY Salary DESC) AS diff_from_max
FROM employees;
實務應用:計算佔比
計算每位員工薪資佔部門最高薪資的百分比:
SELECT
Dept,
Name,
Salary,
ROUND(Salary * 100.0 /
FIRST_VALUE(Salary) OVER (PARTITION BY Dept ORDER BY Salary DESC), 1) AS pct_of_max
FROM employees;
FIRST_VALUE vs MIN / LAST_VALUE vs MAX
雖然在某些情況下結果相同,但它們的用途不同:
| 函數 | 用途 |
|---|---|
| FIRST_VALUE() | 取排序後第一列的「任意欄位值」 |
| MIN() | 取該欄位的最小值 |
| LAST_VALUE() | 取排序後最後一列的「任意欄位值」 |
| MAX() | 取該欄位的最大值 |
例如,如果要找出「薪資最高者的姓名」,只能用 FIRST_VALUE(),因為 MAX() 只能返回薪資數值本身。