LINQ按日期范围做Full Outer Join时如何保留无匹配记录?
解决方案
实现逻辑
外连接场景下不能直接将日期过滤条件写在全局where子句,否则会将外连接生成的无匹配null记录直接过滤,导致丢失「应发未发送」「已发无依据」的两类数据。正确的处理方式是将日期间隔判断放在等值匹配(ID+Type)后的临时结果集中过滤,仅排除ID/Type匹配但发送日期超出2周范围的无效关联,完全无匹配的记录会通过DefaultIfEmpty()保留。
同时可以直接在返回结果中新增状态标记列,满足业务上的三类记录识别需求。
调整后完整代码
// 左外连接:保留所有Table1应发记录,仅关联符合日期要求的已发记录 var leftOuterJoin = from first in table1 join last in table2 on new {A = first.ID, B = first.Type} equals new {A = last.ID, B = last.Type} into temp // 仅保留日期符合2周内要求的匹配记录,再做DefaultIfEmpty from last in temp.Where(t => t.Date >= first.Date && t.Date <= first.Date.AddDays(14)).DefaultIfEmpty() select new { ID = first.ID, Type = first.Type, ShouldSendDate = first.Date, ActualSendDate = last?.Date, Col1 = first.col1, Col2 = first.col2, Col3 = last?.Col3, Col4 = last?.col4, // 直接标记状态 Status = last == null ? "应发未发送" : "匹配成功" }; // 右外连接:保留所有Table2已发记录,仅关联符合日期要求的应发记录 var rightOuterJoin = from last in table2 join first in table1 on new {A = last.ID, B = last.Type} equals new {A = first.ID, B = first.Type} into temp // 仅保留日期符合2周内要求的匹配记录,再做DefaultIfEmpty from first in temp.Where(f => last.Date >= f.Date && last.Date <= f.Date.AddDays(14)).DefaultIfEmpty() select new { ID = last.ID, Type = last.Type, ShouldSendDate = first?.Date, ActualSendDate = last.Date, Col1 = first?.col1, Col2 = first?.col2, Col3 = last.Col3, Col4 = last.col4, Status = first == null ? "已发无对应依据" : "匹配成功" }; // 全外连接:Union会自动去重两边都有的「匹配成功」记录 var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);
改动说明
- 补全了原代码右外连接语法中缺失的
on关键字 - 等值匹配后的临时结果集先做日期过滤,再执行
DefaultIfEmpty(),既排除了超期的无效关联,又不会丢失完全无匹配的记录 - 统一了左右连接返回的匿名类结构,新增
Status字段直接识别记录类型,无需后续二次判断 - 新增了应发日期、实际发送日期的显式返回,方便后续报表校验
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

