如何獲取分組中的首行數據?可使用first_value函數實現。該函數作為窗口函數,通過over子句定義窗口范圍,結合partition by進行分組、order by定義排序,從而獲取每組中第一行的值;例如在sales表中查找每個產品首次銷售金額時,使用partition by product_id并按sale_date排序;還可結合cte計算與首次值的差異;其常見應用場景包括sql server、postgresql、oracle及mysql 8.0+等主流數據庫;與lag和lead不同,前者始終返回分區內的首個值,而后者分別訪問當前行的前后行;若首行值為NULL,first_value將返回null,可通過coalesce處理此類情況。
獲取分組首行數據,FIRST_VALUE 函數就像一個時光機,能讓你在每個分組里瞬間回到過去,拿到第一行的值。
解決方案: FIRST_VALUE 函數主要用于獲取窗口中第一行的值,這個“窗口”通常由 OVER 子句定義,可以按特定列進行分區和排序。
基本語法如下:
FIRST_VALUE (expression) OVER ( [PARTITION BY column1, column2, ...] ORDER BY column3 [ASC | DESC], ... )
- expression: 你想要獲取的值,比如某個列名。
- PARTITION BY: 將結果集分成多個分區,每個分區獨立計算。 如果省略,則整個結果集被視為一個分區。
- ORDER BY: 定義每個分區內行的順序,決定哪一行是“第一行”。
舉個例子,假設你有一個 sales 表,包含 product_id, sale_date, 和 sale_amount 列。你想找出每個產品第一次銷售的金額:
SELECT product_id, sale_date, sale_amount, FIRST_VALUE(sale_amount) OVER (PARTITION BY product_id ORDER BY sale_date ASC) AS first_sale_amount FROM sales;
這個查詢會返回每一行銷售記錄,同時會額外顯示 first_sale_amount 列,該列顯示了該產品最早一次銷售的金額。
FIRST_VALUE 的一個常見用例是計算與第一個值的差異。 比如,你想知道每個產品的每次銷售額與第一次銷售額的差距:
WITH FirstSales AS ( SELECT product_id, sale_date, sale_amount, FIRST_VALUE(sale_amount) OVER (PARTITION BY product_id ORDER BY sale_date ASC) AS first_sale_amount FROM sales ) SELECT product_id, sale_date, sale_amount, first_sale_amount, sale_amount - first_sale_amount AS sale_difference FROM FirstSales;
這段代碼首先用一個 CTE (Common table Expression) 計算出每個產品的第一次銷售額,然后在外部查詢中計算每次銷售額與第一次銷售額的差值。
FIRST_VALUE 在哪些 SQL 數據庫中可用?
FIRST_VALUE 函數在大多數主流 SQL 數據庫中都可用,包括:
不同數據庫的語法可能略有差異,但基本用法相似。 例如,在某些較老的數據庫版本中,你可能需要使用窗口函數的其他變體來模擬 FIRST_VALUE 的行為。
FIRST_VALUE 與 LAG 或 LEAD 有什么區別?
FIRST_VALUE、LAG 和 LEAD 都是窗口函數,但它們的作用不同:
- FIRST_VALUE: 返回窗口中的第一個值。 不管當前行是什么,它總是返回分區中的第一個值。
- LAG: 返回窗口中當前行之前的某一行的數據。 你可以指定偏移量,例如 LAG(value, 1) 返回前一行的數據。
- LEAD: 返回窗口中當前行之后的某一行的數據。 類似于 LAG,你可以指定偏移量。
簡單來說,FIRST_VALUE 關注的是“起點”,LAG 和 LEAD 關注的是“鄰居”。
如果分組中第一行數據為 NULL,FIRST_VALUE 會返回什么?
如果分組中的第一行數據為 NULL,FIRST_VALUE 函數會返回 NULL。 這是符合 SQL 標準的行為。 你需要注意處理 NULL 值的情況,例如使用 COALESCE 函數來替換 NULL 值為一個默認值。
SELECT product_id, sale_date, sale_amount, COALESCE(FIRST_VALUE(sale_amount) OVER (PARTITION BY product_id ORDER BY sale_date ASC), 0) AS first_sale_amount FROM sales;
在這個例子中,如果某個產品的第一次銷售額為 NULL,first_sale_amount 列將顯示為 0。