跨表按日期区间匹配动态控制限值 SQL查询结果重复问题
问题背景
现有两张业务数据库表:
- 明细表
detailTbl:存储年份及对应实际限值数据 - 控制限值表
controlTbl:仅记录特定年份的最大控制限值
业务需求
查询返回全部明细记录,匹配规则为:若明细记录的年份早于控制表中下一个控制限值的记录年份,则拉取对应匹配的控制限值。
现存问题
当前尝试使用右外连接实现逻辑,但查询结果中2015、2016、2017年的数据出现重复,原SQL写法如下:
SELECT d.id, d.yeard, d.value, c.Column1 FROM detailTbl d RIGHT OUTER JOIN controlTbl c ON d.dated <= c.datec
问题原因
原连接逻辑仅判断了明细年份小于等于控制表年份,单条明细记录会匹配到所有满足d.dated <= c.datec的控制表记录。例如2015年的明细会同时匹配2018、2020等所有年份大于2015的控制表条目,最终产生重复数据。
解决方案
核心逻辑是为每条明细记录匹配大于等于该明细年份的最小控制年份对应的控制限值,可根据使用的数据库版本选择写法:
- 通用兼容写法(所有支持子查询的数据库均可用)
SELECT d.id, d.yeard, d.value, c.Column1 FROM detailTbl d LEFT JOIN controlTbl c ON c.datec = ( SELECT MIN(datec) FROM controlTbl WHERE datec >= d.dated )
- 窗口函数高性能写法(支持MySQL8.0+、PostgreSQL、SQL Server、Oracle等主流数据库新版本)
先通过窗口函数给每个控制限值划分生效年份区间,再直接和明细年份做区间匹配,避免子查询反复扫描控制表,数据量大时性能更优:
WITH control_segment AS ( SELECT Column1, datec AS start_year, LEAD(datec, 1, 9999) OVER (ORDER BY datec) AS end_year FROM controlTbl ) SELECT d.id, d.yeard, d.value, c.Column1 FROM detailTbl d LEFT JOIN control_segment c ON d.dated >= c.start_year AND d.dated < c.end_year
内容的提问来源于stack exchange,提问作者oldschool59
相关产品推荐
相关产品推荐

