求对应SQL Server UNBOUNDED PRECEDING窗口函数的C# LINQ查询
问题:将SQL累计求和查询转换为C# LINQ查询
原始数据表
| 日期 | EarnedMHRS | DayVal | MHRS | Per |
|---|---|---|---|---|
| 2022/3/8 | 766 | 0 | 76.61834136 | 0.005743504 |
| 2022/3/9 | 1 | 418.13577 | 0.03134451 | |
| 2022/3/10 | 2 | 1405.189433 | 0.105336539 | |
| 2022/3/11 | 3 | 2907.939774 | 0.21798649 | |
| 2022/3/12 | 4 | 3705.688573 | 0.277787749 | |
| 2022/3/13 | 5 | 2907.939774 | 0.21798649 | |
| 2022/3/14 | 6 | 1405.189433 | 0.105336539 | |
| 2022/3/15 | 7 | 418.13577 | 0.03134451 | |
| 2022/3/16 | 8 | 76.61834136 | 0.005743504 | |
| 2022/3/17 | 9 | 8.645321518 | 0.000648075 |
目标SQL查询
SELECT [Date], SUM(EarnedMHRS) OVER(ORDER BY DayVal ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) As EarnedMHRS, Round(SUM(MHRS) OVER(ORDER BY DayVal ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),0) AS MHRS, per FROM TblPanning;
尝试的LINQ代码(未成功)
decimal? runningTotal = 0; decimal? runningTotalMHRS = 0; var tmpOutput2 = tmpOutput1.Select(item => { runningTotal += item.EarnedMHRS; runningTotalMHRS += item.MHRS; return new { item.Date, MHRS = item.DayVal == totalDays ? totallMhrs : Math.Round(runningTotalMHRS ?? 0, 0), item.per, EarnedMHRS = runningTotal, }; });
期望输出结果
| 日期 | EarnedMHRS | MHRS | per |
|---|---|---|---|
| 2022-03-08 | 766.00 | 77 | 0.00574350382867894 |
| 2022-03-09 | 766.00 | 495 | 0.0313445103804797 |
| 2022-03-10 | 766.00 | 1900 | 0.105336538836155 |
| 2022-03-11 | 766.00 | 4808 | 0.217986488988673 |
| 2022-03-12 | 766.00 | 8514 | 0.277787748142283 |
| 2022-03-13 | 766.00 | 11422 | 0.217986488988673 |
| 2022-03-14 | 766.00 | 12827 | 0.105336538836155 |
| 2022-03-15 | 766.00 | 13245 | 0.0313445103804797 |
| 2022-03-16 | 766.00 | 13321 | 0.00574350382867894 |
| 2022-03-17 | 766.00 | 13340 | 0.000648075073801102 |
解决方案
你的LINQ代码存在两个核心问题:一是未正确处理EarnedMHRS的null值,二是多余的条件判断干扰了累计逻辑。修正后的代码如下:
// 先按DayVal排序,对齐SQL中的ORDER BY逻辑 var sortedData = tmpOutput1.OrderBy(item => item.DayVal).ToList(); decimal runningTotalEarned = 0; decimal runningTotalMHRS = 0; var tmpOutput2 = sortedData.Select(item => { // 处理EarnedMHRS的null值,null时按0累加 runningTotalEarned += item.EarnedMHRS ?? 0; // 累加MHRS runningTotalMHRS += item.MHRS; return new { item.Date, EarnedMHRS = runningTotalEarned, MHRS = Math.Round(runningTotalMHRS, 0), item.per }; });
关键说明
- 必须先排序:SQL窗口函数依赖
ORDER BY DayVal确定累计顺序,LINQ中需要先对数据排序,否则累计结果会混乱。 - null值处理:原始数据中大部分
EarnedMHRS为null,用item.EarnedMHRS ?? 0确保累计时不会出现异常,且结果始终为766。 - 移除多余条件:SQL中没有
item.DayVal == totalDays的逻辑,直接对累计的runningTotalMHRS取整即可对齐目标结果。
内容的提问来源于stack exchange,提问作者avnish maddheshiya
相关产品推荐
相关产品推荐

