用lag()判断连续上涨需先按时间排序计算每行是否上涨,再通过行号差构造分组标识,筛选is_up=true的记录分组统计长度;必须确保order by使用真实时间字段,处理null和相等情况。

如何用 LAG() 判断单次价格变动方向
窗口函数本身不直接“识别连续上涨”,得靠组合逻辑:先算出每条记录相比前一条是涨还是跌,再看这个状态是否连续出现。核心是用 LAG() 取上一行的 price,然后和当前行比较。
常见错误是直接 ORDER BY id 却没考虑时间顺序——如果数据按插入顺序乱序,LAG() 会拿错“前一日”价格。必须确保 ORDER BY 依据的是真实业务时间字段(比如 trade_time 或 date)。
SELECT *, price > LAG(price) OVER (ORDER BY date) AS is_up- 注意
LAG(price, 1)默认就是取前 1 行,显式写LAG(price)即可 - 第一行的
LAG()返回NULL,price > NULL结果为NULL,建议用COALESCE(is_up, FALSE)统一处理
用 ROW_NUMBER() 和分组识别连续段
判断“连续”本质是把相邻的 is_up = TRUE 记录归到同一组里。标准做法是构造一个“分组标识”:用全局行号减去按 is_up 分组后的行号,相同差值即为同一连续段。
容易踩坑的是漏掉 WHERE is_up 过滤——如果不先筛出上涨行,FALSE 值也会参与分组计算,导致连续段被错误打断。
- 先生成带
is_up的临时结果(CTE 或子查询) - 对所有
is_up = TRUE的行,计算:ROW_NUMBER() OVER (ORDER BY date) - ROW_NUMBER() OVER (PARTITION BY is_up ORDER BY date) - 这个差值就是连续上涨段的 ID,再用
COUNT(*)算每段长度
性能与边界情况提醒
当数据量大(比如百万级交易记录)时,嵌套 CTE 多层窗口函数可能变慢。PostgreSQL 和 MySQL 8.0+ 支持,但 SQLite 直接不支持窗口函数;SQL Server 需 2012+ 版本。
边界情况常被忽略:
- 价格相等(
price = LAG(price))算“未上涨”,必须用>而非>= - 同一天多条记录:若
date字段精度只到日,需补充id或time二级排序,否则LAG()结果不确定 - 连续上涨 2 天 vs 至少 3 天:筛选条件写成
HAVING COUNT(*) >= 3,别漏掉=
一个可跑的最小示例
WITH price_diff AS (
SELECT
date,
price,
price > LAG(price) OVER (ORDER BY date) AS is_up
FROM stock_prices
),
up_streaks AS (
SELECT
date,
price,
ROW_NUMBER() OVER (ORDER BY date)
- ROW_NUMBER() OVER (PARTITION BY is_up ORDER BY date) AS grp
FROM price_diff
WHERE is_up
)
SELECT
MIN(date) AS start_date,
MAX(date) AS end_date,
COUNT(*) AS days
FROM up_streaks
GROUP BY grp
HAVING COUNT(*) >= 3;
真正难的不是写对这几句 SQL,而是确认 date 字段是否唯一、是否含时区偏移、有没有脏数据导致 LAG() 拿到异常值——这些往往比语法更耗调试时间。










