订阅更新

SQL 怎么求最长连续增长天数?只判断今天大于昨天够吗?

面试问 301 约 4 分钟读完

本文目录
  1. 面试怎么回答
  2. 先确定输入是不是一天一行
  3. 用断点,而不是用增长总次数
  4. 三个观察日,不等于三次增长
  5. 一个典型场景:跨过缺日,长区间被算出来了
  6. 筛选日期放在哪里,也会改变答案
  7. 资料与适用边界

面试怎么回答

我会先整理成每天一行,明确缺日和真实零值。用LAG取前一天日期和指标,只有日期相邻且数值严格增加才延续当前段,否则标记新段;累计断点得到分组,再统计各段长度。最后区分观察日数和增长次数,三天递增只有两次增长。NULL、相等值、缺日和并列最长都要测试,不能把所有增长标记简单相加。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

销售额依次是10、20、15、25,增长发生了两次,但并没有连续增长四天。把“今天比昨天高”的标记求和,得到的是增长次数,不是最长连续区间。这道SQL题最容易漏的,还有中间缺一天怎么办。

连续增长要同时满足日期相邻和数值递增;先标记断点再分段,最后明确统计观察日还是增长次数。

先确定输入是不是一天一行

如果原始数据是订单明细,应先按业务日期汇总;同一天多行直接LAG,比较的可能是同一天的两笔订单,而不是两天销售额。

缺日也不等于零。业务确认没有交易,可以补成零;采集缺失或数据未完成,则应保留未知,通常不能让连续增长跨过去。

日期需要按同一业务时区生成。下面SQL以PostgreSQL 17的DATE字段为例,假设日表每天唯一,金额字段允许NULL。

用断点,而不是用增长总次数

WITH prev AS (
  SELECT dt, amount,
         LAG(dt) OVER (ORDER BY dt) AS prev_dt,
         LAG(amount) OVER (ORDER BY dt) AS prev_amount
  FROM daily_sales
), marked AS (
  SELECT *,
         CASE WHEN dt = prev_dt + 1
                    AND amount > prev_amount
              THEN 0 ELSE 1 END AS new_group
  FROM prev
), grouped AS (
  SELECT *,
         SUM(new_group) OVER (
           ORDER BY dt ROWS UNBOUNDED PRECEDING
         ) AS group_no
  FROM marked
)
SELECT MIN(dt) AS start_dt, MAX(dt) AS end_dt,
       COUNT(*) AS observation_days,
       COUNT(*) - 1 AS increase_count
FROM grouped
WHERE amount IS NOT NULL
GROUP BY group_no
ORDER BY observation_days DESC, start_dt;

这里未截取第一行,是为了保留并列最长区间,读者可按需要筛选最大长度。若有多个商品,应在每个窗口里加入相同商品分区,并在最终分组中包含商品键。

当前值或前值为空时,比较不成立,会形成断点。NULL行在分段后才过滤,不能提前删除后让两侧数据在错误的时间语义下相连。

最长增长:先找关系,再找分段

三个观察日,不等于三次增长

1日10元、2日20元、3日30元,这一段有三个观察日,但只有两条增长关系:1日至2日、2日至3日。

业务说“连续增长三天”时,可能想要连续三次日环比增长,那就需要四个连续观察日。指标字段最好直接叫观察日数或增长次数,避免口头表达掩盖一位偏差。

严格增长使用大于;如果允许相等,是非下降序列,需要改条件并改指标名称。不能实现时偷偷改成大于等于,解释时仍说每天都在增长。

一个典型场景:跨过缺日,长区间被算出来了

比如1日10元、2日20元、4日30元,程序只比较金额,得到三行持续递增,于是报告连续增长三天。

最初怀疑日期排序错误,排序检查却完全正常。根因是相邻记录不等于相邻日期,3日缺失没有参与断点判断。

旧样本每天都有记录,只测金额上升和下降,未覆盖缺日。修复增加日期相邻条件,并区分可确认的零业务和未知缺失。

如果3日确实零销售且补零,增长段又会不同;这正说明补齐不是纯技术步骤,而是决定序列含义的一部分。

筛选日期放在哪里,也会改变答案

只读取最近七天后分段,得到的是七天窗口内最长片段,不一定是完整历史连续增长长度。

如果要回答“截至今天已经连续增长多久”,可能需要向前追溯到真正断点;只补昨天一行,也只能判断第一条边界关系,不能恢复任意长的历史区间。

验收可以用全增、全降、相等、缺日、NULL、单行与并列最长七类数据。空输入应明确返回空结果还是业务展示零,不要让下游猜测。

这道题的重点不是窗口函数写得多复杂,而是把相邻关系、断点和长度三个概念定义一致,再让SQL逐层实现。

资料与适用边界

机制以所链接版本为准;业务示例用于说明判断方法,不代表作者真实项目或已验证的生产性能。

刷题进度保存在当前浏览器