02 | 波峰波谷问题


目录

一、问题定义与业务场景

二、数据准备与建表语句

2.1 建表语句

2.2 样例数据

三、SQL解决方案(窗口函数法)

3.1 核心思路

3.2 完整代码

3.3 执行步骤解析

四、扩展优化

五、总结


一、问题定义与业务场景

目标:从股票每日收盘价中识别价格波峰(Peak)和波谷(Trough)的日期及价格。
定义

  • 波峰:当日价格严格高于前一天 高于后一天。
  • 波谷:当日价格严格低于前一天 低于后一天。

二、数据准备与建表语句

2.1 建表语句

CREATE TABLE t_stock (
    ts_code VARCHAR(20) COMMENT '股票代码',  -- 如 '000001.SZ'
    trade_date DATE COMMENT '交易日期',      -- 日期类型避免字符串比较
    close_price FLOAT COMMENT '收盘价',            -- 浮点型存储价格
    PRIMARY KEY (ts_code, trade_date)       -- 复合主键防重复
) COMMENT '股票交易日行情表';

字段设计规范

  • 股票代码VARCHAR(20),兼容交易所格式(如深交所代码后缀.SZ)。
  • 交易日期DATE类型(非VARCHAR),避免日期格式混乱,支持日期计算。
  • 收盘价FLOAT足够存储价格,若需高精度可改用DECIMAL(10,2)
  • 主键(ts_code, trade_date) 复合主键,防止同一股票同日重复记录。

2.2 样例数据

INSERT INTO t_stock (ts_code, trade_date, close_price) VALUES
('000001.SZ', '2025-06-04', 16.66),  -- 不参与计算
('000001.SZ', '2025-06-05', 17.15),  -- 波峰
('000001.SZ', '2025-06-06', 17.12),  -- 波谷
('000001.SZ', '2025-06-07', 17.20),  -- 波峰
('000001.SZ', '2025-06-10', 17.19),  -- 波谷
('000001.SZ', '2025-06-11', 17.41);  -- 不参与计算

数据特点

  • 同一股票多日连续价格,需按日期排序。
  • 边缘日期(首日/末日)无前驱或后继,不参与波峰波谷计算。

三、SQL解决方案(窗口函数法)

3.1 核心思路

  • 通过 lag() 函数获取上一天的收盘价;通过 lead() 函数获取下一天的收盘价
  • 过滤出满足波峰波谷条件的记录

3.2 完整代码

SELECT
  ts_code,
  trade_date,
  close_price,
  price_type 
FROM
  (
  SELECT
    ts_code,
    trade_date,
    close_price,
    CASE WHEN close_price > prev_close_price AND close_price > next_close_price THEN '波峰' 
        WHEN close_price < prev_close_price AND close_price < next_close_price THEN '波谷' 
    END AS price_type  
  FROM
    (
    SELECT
      ts_code,
      trade_date,
      close_price,
      LAG( close_price, 1 ) OVER ( PARTITION BY ts_code ORDER BY trade_date ) AS prev_close_price,
      LEAD( close_price, 1 ) OVER ( PARTITION BY ts_code ORDER BY trade_date ) AS next_close_price 
    FROM
      t_stock 
    ) t1 
  ) t2 
WHERE
  price_type IN ( '波峰', '波谷' );

计算结果:

3.3 执行步骤解析

步骤

关键操作

作用

1. 子查询

LAG(close_price,1)

取前一日价格

LEAD(close_price,1)

取后一日价格

2. 主查询

比较close_price > prev_close_price AND close_price > next_close_price

识别波峰

比较close_price < prev_close_price AND close_price < next_close_price

识别波谷

3. 过滤

WHERE条件

排除非波峰波谷


四、扩展优化

1. 边缘情况处理

  • 首尾日期:天然无法满足双比较条件,SQL自动排除。
  • 价格相等:严格不等条件(>/<)会跳过相等情况(如三日价格持平)。

2. 性能优化

  • 索引设计(加速窗口函数):
CREATE INDEX idx_stock_code_date ON t_stock(ts_code, trade_date);
  • 分区表:按股票代码分区,减少全表扫描。

五、总结

  • 核心方法LAG()/LEAD()窗口函数是波峰波谷问题的标准解法,避免自连接的低效操作。
    • lag()函数:LAG(col, n, DEFAULT) 用于统计窗口内往上第 n 行。参数 1 为列名,参数 2 为往上第 n 行(可选,默认为1),参数 3 为默认值(当往上第 n 行为 NULL 时,取默认值,如不指定,则为NULL)
    • lead()函数:LEAD(col, n, DEFAULT) 用于统计窗口内往下第 n 行。参数 1 为列名,参数 2 为往下第 n 行(可选,默认为1),参数 3 为默认值(当往下第 n 行为 NULL 时,取默认值,如不指定,则为NULL)
  • 建表关键:日期字段用DATE类型、复合主键防重复、索引加速排序。
  • 面试要点:明确边界条件(首尾剔除)、理解窗口函数执行顺序、索引优化意识。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走过冬季

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值