要按顺序取最小值需结合order by与rows between子句,语法为:min(column_name) over (order by order_column rows between unbounded preceding and current row),1. min(column_name)指定计算最小值的列;2. over()定义窗口范围;3. order by指定排序方式;4. rows between表示从第一行到当前行。此方法可用于分析趋势、累计统计等场景,如计算历史最低销售额、股票最低价、玩家最佳成绩等,使用时注意排序字段应唯一或有序,建议显式指定窗口范围以确保准确性。

在 SQL 中,MIN() OVER() 通常用来计算窗口内的最小值。但如果你希望它“按顺序取最小值”,就需要结合 ORDER BY 子句来控制窗口的排序和范围。

简单来说:你想让每一行都看到前面所有数据中的最小值,而不是整个字段的全局最小值。这在分析趋势、累计统计等场景中非常有用。

如何用 MIN() OVER() 结合 ORDER BY
基本语法如下:
MIN(column_name) OVER (ORDER BY order_column ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
-
MIN(column_name)是你要找的最小值列。 -
OVER()定义了窗口函数的范围。 -
ORDER BY order_column指定了排序方式。 -
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW表示从第一行开始,到当前行为止。
这样写的意思是:每一行都会看到从第一行到当前行之间所有数据的最小值。

举个例子:
假设你有如下销售记录表(sales):
| date | amount |
|---|---|
| 2023-01-01 | 100 |
| 2023-01-02 | 80 |
| 2023-01-03 | 90 |
| 2023-01-04 | 70 |
你想知道每一天之前(包括当天)的最低销售额,可以这样写:
SELECT date, amount, MIN(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS min_so_far FROM sales;
结果会是:
| date | amount | min_so_far |
|---|---|---|
| 2023-01-01 | 100 | 100 |
| 2023-01-02 | 80 | 80 |
| 2023-01-03 | 90 | 80 |
| 2023-01-04 | 70 | 70 |
可以看到,min_so_far 是随着日期递增不断更新的“历史最小值”。
注意事项与常见问题
-
排序字段必须唯一或有序:如果
ORDER BY的字段有重复值,可能会影响窗口范围的划分,导致结果不准确。 -
默认窗口范围不一定符合预期:如果不加
ROWS BETWEEN ...,有些数据库默认只包括从第一行到当前行的所有行,但有些则不同。建议显式指定范围更稳妥。 -
分区字段可选:如果你的数据需要分组处理(比如每个用户单独计算),可以加上
PARTITION BY user_id。
例如:
MIN(amount) OVER (PARTITION BY user_id ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
实际应用场景
这种技巧常用于:
- 股票价格走势中计算“历史最低价”
- 销售数据分析中查看“截止某天为止的最低销量”
- 游戏排行榜中记录玩家的历史最佳成绩
只要涉及到随时间变化的累计最小值,都可以考虑使用这个方法。
基本上就这些,虽然看起来有点复杂,但其实逻辑很简单:先排好序,再定义窗口范围,然后取最小值。掌握后你会发现它真的很实用。










