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 資料表:

DeptNameSalary
業務張一55000
業務王二50000
研發李三70000
研發趙四60000

取得各部門薪資最高者的姓名:

SELECT 
    Dept,
    Name,
    Salary,
    FIRST_VALUE(Name) OVER (PARTITION BY Dept ORDER BY Salary DESC) AS top_earner
FROM employees;

查詢結果:

DeptNameSalarytop_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() 只能返回薪資數值本身。