【问题标题】:translate row_number over partition to C# linq将分区上的 row_number 转换为 C# linq
【发布时间】:2020-10-29 07:43:29
【问题描述】:

如何将以下 SQL 查询转换为 C# Linq:

SELECT * FROM (
   SELECT *, ROW_NUMBER() OVER (PARTITION BY StuffConditionId, StuffId ORDER BY StuffDayOfYear) AS RowNumber
   FROM Stuff) rop
WHERE rop.RowNumber = 1;

这是部分数据集:

StuffId,StuffValue,StuffConditionId,StuffDayOfYear
2,9340,NULL,1
2,9340,NULL,2
2,9340,NULL,3
11,78,NULL,267
11,78,NULL,268
11,78,NULL,269
43,0,3,130
43,0,3,131
43,0,3,132
43,0,2,133
45,0,2,134
45,0,2,135
45,0,2,148
55,0,2,309
55,0,2,332
55,0,3,333

答案摘要:答案是首先在内存中构建一个东西列表,即本地列表变量,然后应用 LINQ 查询,如下面的答案所示。

【问题讨论】:

  • 没有额外的扩展 - 没办法。 stackoverflow.com/questions/64412492/…
  • 使用 GroupBy 然后您可以使用 Select 上的第二个参数,它会为您提供索引。但是,每个 GroupBy 上的 GroupBy、OrderBy 和 First 也将实现此结果。给我一些上述查询的示例数据和相关的 SQL 结果,我将为您制作 Linq 查询。
  • 严格意义上来说,SvyatoslavDanyliv 是对的,但 Carlo Bos 注意到 WHERE 子句意味着 OP 实际上只是试图从每个组中获取顶部项目。根据您使用的 ORM 版本,这可能是可能的。

标签: c# sql-server linq


【解决方案1】:

如果没有一些实际数据,我无法对此进行测试。但假设stuff 是您的收藏(又名表),请按照以下方式完成:

var firstInCollection = Stuff
    .OrderBy(x => x.StuffDayOfYear)
    .ToList() // Load in memory, then do groupby and select first due to EF Core
    .GroupBy(x => new { condition = x.StuffConditionId, stuff = x.StuffId })
    .Select(g => g.First());

好的,我已经在包含国家/地区列表的数据表上进行了尝试。这是我的结果:

SELECT *
FROM (
   SELECT *, ROW_NUMBER() OVER (PARTITION BY SUBSTRING(CountryCode, 1, 1) ORDER BY CountryCode) AS RowNumber
   FROM Lookup.Country) rop
WHERE rop.RowNumber = 1;

并在 SQL 中得到以下结果

然后我使用了下面的 Linq 语句。这是在连接到我的 Microsoft SQL 数据库的 LinqPad 中使用 Linq2SQL:

Countries
    .OrderBy(c => c.CountryName)
    .GroupBy(c => c.CountryName[0])
    .Select(g => g.First())

得到以下结果:

这与 SQL 结果相关。

这是您的示例数据的示例

void Main()
{
    var stuffs = new []
    {
        new Stuff { StuffId =  2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 1   },
        new Stuff { StuffId =  2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 2   },
        new Stuff { StuffId =  2, StuffValue = 9340, StuffConditionId = null, StuffDayOfYear = 3   },
        new Stuff { StuffId = 11, StuffValue =   78, StuffConditionId = null, StuffDayOfYear = 267 },
        new Stuff { StuffId = 11, StuffValue =   78, StuffConditionId = null, StuffDayOfYear = 268 },
        new Stuff { StuffId = 11, StuffValue =   78, StuffConditionId = null, StuffDayOfYear = 269 },
        new Stuff { StuffId = 43, StuffValue =    0, StuffConditionId =    3, StuffDayOfYear = 130 },
        new Stuff { StuffId = 43, StuffValue =    0, StuffConditionId =    3, StuffDayOfYear = 131 },
        new Stuff { StuffId = 43, StuffValue =    0, StuffConditionId =    3, StuffDayOfYear = 132 },
        new Stuff { StuffId = 43, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 133 },
        new Stuff { StuffId = 45, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 134 },
        new Stuff { StuffId = 45, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 135 },
        new Stuff { StuffId = 45, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 148 },
        new Stuff { StuffId = 55, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 309 },
        new Stuff { StuffId = 55, StuffValue =    0, StuffConditionId =    2, StuffDayOfYear = 332 },
        new Stuff { StuffId = 55, StuffValue =    0, StuffConditionId =    3, StuffDayOfYear = 333 }
    };


    var firstInCollection = stuffs
        .OrderBy(x => x.StuffDayOfYear)
        .GroupBy(x => new { condition = x.StuffConditionId, stuff = x.StuffId })
        .Select(g => g.First())
        .Dump();
}

class Stuff
{
    public int StuffId { get; set; }
    public int StuffValue { get; set; }
    public int? StuffConditionId { get; set; }
    public int StuffDayOfYear { get; set; }
}

这会导致以下结果:

【讨论】:

  • 我刚刚尝试了我的数据,它返回一个空的 EntityQueryable,我认为这适用于一个分区变量,如果您尝试多个像我这样的分区变量,它会有问题
  • 我刚刚意识到我需要在匿名类中命名属性(当属性超过 1 个时)。不过,这对我有用。我已经更新了上面的答案。此行:.GroupBy(x => new { condition = x.StuffConditionId, stuff = x.StuffId })
  • 我最近了解到GroupBy().Select(g => g.First()) 在 EF Core 中不起作用(在 EF Core 2 中它将使用内存中评估,而在 EF Core 3 中它将引发异常)。因此,如果您希望很快切换到 .NET Core,请注意这一点。
  • 我刚刚用命名的 groupby 变量尝试了更新的答案,仍然是相同的空集合。 @Stripling,我为此使用 .net core 3.1。
  • 很抱歉它与 EF Core 不兼容。我已经用您的示例数据尝试了解决方案,它似乎返回了一个结果。我已经更新了上面的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-24
  • 2014-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多