如何获取分组中的首行数据?可使用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。