SQL 同比一定是日期减一年吗?闰年和同星期怎么对齐?
面试怎么回答
我会先确认同比是自然月日、同星期还是活动阶段对齐,再通过版本化日期映射关联基期。闰日、跨年周和移动节假日需要明确例外,不能统一减365天。计算时还要对齐完整性和截至时点,检查映射是否一对一,避免基期金额被重复累计。变化率最后计算,基期为零或缺失分别展示,不让公式替代业务判断。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
今年周末的销售额比去年同月同日高很多,业务却说:“去年那天是工作日,这样比不公平。”开发没有算错减法,双方只是把不同的比较关系都叫作同比。面试追问到闰年和节假日时,考的就是这层口径。
同比先定义可比日期关系,再计算变化率;自然日、同星期和活动日历回答的是不同问题。
三种“去年”,其实不是一回事
自然日同比比较同月同日,适合有明确日历日期意义的业务;同星期比较则尽量匹配星期结构,常用于周内波动明显的经营数据。
活动同比可能比较活动开始后的第几天,或者相同节日阶段。节日在公历上移动时,硬找去年同月同日,未必有业务解释力。
没有一种口径永远正确。关键是让指标名称、日期映射和解释一致,不能图表写自然日同比,SQL却使用固定天数偏移,讲解时又按节日周期解释。
减一年、减365天、减52周,不能互换
日期减365天是在固定天数上移动,跨过闰日时未必得到相同月日。减52周保持星期,但一年通常不止52整周,长期看会与自然日产生偏移。
按月或年间隔运算又涉及目标日期是否存在,例如2月29日映射到非闰年。数据库有自身的日期运算规则,但业务仍要决定闰日是单独展示、合并到某日,还是不做日级比较。
推荐将目标日、基期日、比较类型和规则版本放在业务日历映射里。SQL只负责执行确认后的关系,避免每张报表各自写一套例外。

日期配上了,还要对齐数据进度
今天只到上午十点,去年对应日却取了全天,得到的下降率没有可比性。应比较同样的截至时点,或者只对完整日计算。
源数据晚到也会造成假下降。当前日尚未完整、基期已结算完成,即使两边时间条件相同,数据成熟度仍可能不同。需要标识暂估与已确认。
时区应在进入日历映射前统一。跨国家经营不一定所有地区共享一个业务日,不能先按UTC聚合,再拿本地日历解释同比。
一个典型场景:两天都映射到去年同一天
比如为了处理闰年,将2月28日和2月29日都映射到去年2月28日。单日图上都有可展示的比较值,看上去没有问题。
到了月底,报表把日级基期金额再次求和,去年2月28日被加了两次。最初以为历史表多了一行,实际根因是日期映射多对一。
旧验收只检查每个当前日能找到基期,没有检查基期被引用次数。修复需要为月度同比单独定义月度范围,或明确闰日分配规则,不能直接汇总重复展示的日比较值。
因此日同比能够显示,不代表日同比分母可以无条件累加成月同比。日期映射和预算重复展示一样,都有可加总边界。
让映射成为可验收的数据
检查当前日期是否唯一映射、基期是否重复引用、映射日期是否存在,以及比较期间的工作日和节假日结构是否符合约定。
跨年周尤其要区分日历年与周所属年。年初几天可能归属上一周年度,简单拼接“年份+周号”可能关联到错误周期;有周口径需求时,直接维护明确的周标识更稳妥。
最后才计算变化率:本期减基期,再除以基期。基期为零、没有可比日期、数据未到齐,应是不同状态,不要统一填零。
测试至少包含闰日、年末年初、移动节假日、当前半日和多对一映射。面试里把这些例外讲成一套规则,比背出一个日期函数更接近真实报表设计。
资料与适用边界
机制以所链接版本为准;业务示例用于说明判断方法,不代表作者真实项目或已验证的生产性能。