使用Linq按填充顺序查询tblSpace累计Available值达阈值的行
Linq实现逐行累加取数方案
核心规则
针对MSSQL数据表tblSpace,需严格按照填充顺序(1到5的优先级)逐行选取,累加每行Available字段值,直到累加和大于等于传入的目标数值,返回所有已选取的行。
预期校验场景:
- 传入值为9000时,仅返回Vienguard行(单行Available值10000≥9000,满足要求)
- 传入值为23000时,返回Vienguard、Halestorm两行(两行累加值10000+15000=25000≥23000,满足要求)
- 传入值为35000时,返回Vienguard、Halestorm、Quarts三行(三行累加值10000+15000+20000=45000≥35000,满足要求)
实现代码
1. 内存集合/数据已加载到本地场景
如果已经把表数据拉取到本地内存,直接用TakeWhile配合累计变量实现即可,逻辑简洁性能高:
// 传入的目标阈值,可替换为实际入参 int target = 35000; long accumulate = 0; var queryResult = tblSpaceList .OrderBy(item => item.FillOrder) // *必须先按填充顺序升序排列,否则会出现选行顺序错误* .TakeWhile(item => { // 累计值已经达标就停止选取 if (accumulate >= target) return false; accumulate += item.Available; return true; }) .ToList();
2. EF Core直连数据库场景
如果要直接在数据库侧执行查询、避免全表数据加载到内存,可通过累计子查询实现(EF Core 3.0+可正常翻译为MSSQL执行语句):
int target = 35000; var queryResult = dbContext.tblSpace .OrderBy(item => item.FillOrder) // *必须先按填充顺序升序排列,否则会出现选行顺序错误* .Select(item => new { CurrentRow = item, // 计算截止当前行的Available累计值 TotalToCurrent = dbContext.tblSpace .Where(s => s.FillOrder <= item.FillOrder) .Sum(s => s.Available) }) // 只要截止上一行的累计值还没达标,就需要选取当前行 .TakeWhile(stat => stat.TotalToCurrent - stat.CurrentRow.Available < target) .Select(stat => stat.CurrentRow) .ToList();
逻辑说明
该实现不会做多余遍历:
- 第一行判断时初始累计值为0,必然小于目标值,选中第一行后累加对应Available值
- 后续每行先判断当前累计值是否已经达标,达标就直接终止遍历,无额外计算开销
- 完全匹配按顺序累加、达标即止的要求,所有预期场景均可正确返回结果
内容的提问来源于stack exchange,提问作者Alexander Raymak
相关产品推荐
相关产品推荐

