SQL Server 2012 引入的視窗函數 FIRST_VALUE、LAST_VALUE 讓我們能在單一掃描中取得分區內第一筆與最後一筆的值,大幅簡化「首次/最近一次購買」、「每日首筆/尾筆交易」等查詢。
FIRST_VALUE(scalar_expression) OVER ([PARTITION BY ...] ORDER BY ...)
LAST_VALUE(scalar_expression) OVER ([PARTITION BY ...] ORDER BY ...)
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。LAST_VALUE 預設只看到「目前列至開頭」,不會看到後面的列,必須顯式指定 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 才能取得真正的分區最後一筆。WITH test AS (
SELECT N'樂可樂可的部落格' AS name, 10 AS score UNION ALL
SELECT N'樂可樂可的部落格', 15 UNION ALL
SELECT N'樂可樂可的部落格', 20 UNION ALL
SELECT N'微軟認證', 30 UNION ALL
SELECT N'微軟認證', 40 UNION ALL
SELECT N'微軟認證', 40
)
SELECT
name, score,
FIRST_VALUE(score) OVER (PARTITION BY name ORDER BY score) AS first_score,
LAST_VALUE(score) OVER (
PARTITION BY name ORDER BY score
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_score
FROM test;
| name | score | first_score | last_score |
|---|---|---|---|
| 樂可樂可的部落格 | 10 | 10 | 20 |
| 樂可樂可的部落格 | 15 | 10 | 20 |
| 樂可樂可的部落格 | 20 | 10 | 20 |
| 微軟認證 | 30 | 30 | 40 |
| 微軟認證 | 40 | 30 | 40 |
| 微軟認證 | 40 | 30 | 40 |
FIRST_VALUE:依 ORDER BY score 取分區最小值(10、30)。LAST_VALUE:加上完整視窗框架後,取分區最大值(20、40)。PARTITION BY user_id ORDER BY login_time。PARTITION BY stock_id, trade_date ORDER BY trade_time。| 函數 | 用途 | 是否需完整視窗框架 |
|---|---|---|
| LEAD/LAG | 取相對位移(下一筆/上一筆) | 否 |
| FIRST_VALUE | 取分區第一筆 | 否(預設即可) |
| LAST_VALUE | 取分區最後一筆 | 是(必須指定 UNBOUNDED FOLLOWING) |
FIRST_VALUE 開箱即用;LAST_VALUE **務必加上 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING**,否則只會回傳目前列自身值。掌握這兩個函數,配合 PARTITION BY,能以極簡潔的 SQL 解決「分組首尾」類需求。