Sybase(T-SQL)一对多关联查询:筛选所有关联保险记录date_resolved为NULL的案件号
date_resolved全为NULL的案件号 先理清楚问题和场景
咱们有两张表:cases存案件基本信息,insurance存每个案件对应的多条保险记录,结构如下:
cases表:仅包含casenum(案件号)字段insurance表:包含ins_id、date_resolved(结案日期)、case_num(关联案件号)字段
需求很明确:只返回那些所有关联保险记录的date_resolved都是NULL的案件号。但之前写的查询都跑偏了——比如某个案件有3条保险记录,2条NULL、1条有值,结果也被查出来了,这显然不符合要求。
为啥之前的语句不对?
先拆解下你试过的两个语句的问题:
左连接子查询的写法:
select casenum from cases left join (select date_resolved from insurance where date_resolved is null) ins on ins.case_num = cases.casenum这个语句只把
insurance里date_resolved为NULL的记录挑出来和案件关联,只要案件有一条这样的记录就会被选中,完全没排查这个案件是不是还有其他非NULL的保险记录。内连接加where条件的写法:
select casenum from cases inner join insurance on cases.casenum = insurance.case_num where insurance.date_resolved is null这个逻辑更直接:找出所有存在至少一条
date_resolved为NULL的保险记录的案件,但同样没过滤掉那些同时有非NULL记录的案件。
正确的解法来了!
核心思路是:先对每个案件的保险记录分组,用聚合函数判断该案件的所有date_resolved是否全为NULL。这里用max(date_resolved)非常合适——因为NULL在聚合函数中会被忽略,如果所有记录都是NULL,max()的结果就是NULL;只要有一条记录的date_resolved有值,max()就会返回那个非NULL的值,这样就能通过having子句把这类不符合要求的案件排除掉。
最终可用的T-SQL语句(你可以根据实际需求添加cases表的其他字段和筛选条件):
select casenum, -- 这里可以添加cases表的其他字段 *other stuff* from cases inner join ( select i.case_num from insurance i group by i.case_num having max(date_resolved) is null ) ins on ins.case_num = cases.casenum where *other stuff from cases table* and *more stuff from cases table*
额外补充
如果你的业务需求需要包含没有任何关联保险记录的案件(也就是该案件在insurance表中无对应记录),可以把inner join改成left join,并在where子句中添加ins.case_num is null的条件,具体可根据实际场景调整。
内容的提问来源于stack exchange,提问作者boog




