基于条件计算tick_lower首个有效值tick_lower_position的SQL求解
问题与解决方案
现有数据表ticks
| datetime | lowest_tick | tick_lower |
|---|---|---|
| 2022-10-01 00:02:00 | 204406 | 204306 |
| 2022-10-01 00:03:00 | 204525 | 204425 |
| 2022-10-01 00:04:00 | 204414 | 204314 |
| 2022-10-01 00:05:00 | 204200 | 204100 |
| 2022-10-01 00:06:00 | 204220 | 204120 |
| 2022-10-01 00:07:00 | 204120 | 204020 |
需求说明
需要生成tick_lower_position字段:
- 取值为满足
tick_lower <= lowest_tick条件的首个tick_lower值 - 后续行沿用该值,直到出现下一次满足条件的新值
期望结果表
| datetime | lowest_tick | tick_lower | tick_lower_position |
|---|---|---|---|
| 2022-10-01 00:02:00 | 204406 | 204306 | 204306 |
| 2022-10-01 00:03:00 | 204525 | 204425 | 204306 |
| 2022-10-01 00:04:00 | 204487 | 204387 | 204306 |
| 2022-10-01 00:05:00 | 204200 | 204100 | 204100 |
| 2022-10-01 00:06:00 | 204220 | 204120 | 204100 |
| 2022-10-01 00:07:00 | 204120 | 204020 | 204100 |
原方案问题分析
你尝试的基于lag()的分组方案逻辑不符合当前需求,错误触发了分组条件,导致第三行的tick_lower_position取值错误。
正确解决方案
核心思路:
- 标记所有满足
tick_lower <= lowest_tick的行作为"锚点" - 基于锚点分组,让锚点后的所有行归属到最近的上一个锚点分组
- 在每个分组内取锚点的
tick_lower值作为全组的tick_lower_position
对应的SQL语句:
SELECT t.*, FIRST_VALUE(tick_lower) OVER (PARTITION BY group_id ORDER BY datetime) AS tick_lower_position FROM ( SELECT *, SUM(CASE WHEN tick_lower <= lowest_tick THEN 1 ELSE 0 END) OVER (ORDER BY datetime) AS group_id FROM ticks ) t ORDER BY datetime;
逻辑解释
- 内层子查询通过
SUM(CASE...) OVER(ORDER BY datetime)生成group_id:每遇到一个满足条件的锚点行,分组ID递增,后续不满足条件的行继承当前分组ID,直到下一个锚点出现。 - 外层通过
FIRST_VALUE(tick_lower)在每个分组内取首个锚点的tick_lower值,作为该组所有行的tick_lower_position。
内容的提问来源于stack exchange,提问作者Ivan Roptanov
相关产品推荐
相关产品推荐

