【问题标题】:LINQ (to Oracle) - Row_Number() Over Partition ByLINQ (to Oracle) - Row_Number() Over Partition By
【发布时间】:2013-02-24 07:27:23
【问题描述】:

这可能与其他 Partition By + Rank 问题重复,但我发现这些问题/答案中的大多数都过于特定于其特定的业务逻辑。我正在寻找的是以下类型查询的更通用的 LINQ 版本:

SELECT id,
       field1,
       field2,
       ROW_NUMBER() OVER (PARTITION BY id
                          ORDER BY field1 desc) ROWNUM
FROM someTable;

我们对此做的一个非常常见的事情是把它包装成这样的东西:

SELECT id,
       field1,
       field2
FROM (SELECT id,
      field1,
      field2,
      ROW_NUMBER() OVER (PARTITION BY id
                         ORDER BY field1 desc) ROWNUM
      FROM someTable)
WHERE ROWNUM = 1;

它返回包含每个 id 的 field1 中的最大值的行。将 order by 更改为 asc 当然会返回最小值或将等级更改为 2 将获得第二高/最低值等,等等。有没有办法编写一个可以在服务器端执行的 LINQ 查询,这给了我们相同的功能?理想情况下,性能与上述一样。

编辑: 在搜索网络后,我尝试了许多不同的解决方案,它们最终都给了我与 Reed 下面的答案相同的问题,因为生成的 SQL 包含一个APPLY

我试过的几个例子:

from p in db.someTable
group p by p.id into g
let mostRecent = g.OrderByDescending(o => o.field1).FirstOrDefault()
select new {
    g.Key,
    mostRecent
};

db.someTable
    .GroupBy(g => g.id, (a, b) => b.OrderByDescending(o => o.field1).Take(1))
    .SelectMany(m => m);

这两种方法都会导致非常相似(如果不相同)的 SQL 代码使用 Oracle 不支持的 OUTER APPLY

【问题讨论】:

  • 对我来说,这似乎是一个简单的 GROUP BY idMAX(field1)。我错过了什么吗?
  • @FrancisP 以目前的形式,是的。但是如果我不想要 MAX 而想要第二个或第三个呢?我已经删除了对那个特定部分的强调。
  • @Kittoes 同样的技术应该可以通过添加一个Skip 调用然后过滤掉任何空结果......

标签: sql-server linq oracle entity-framework


【解决方案1】:

另一种方法,通过使用子查询分别获取每个ID 的最大值field1

SELECT  a.*
FROM    someTable a
        INNER JOIN
        (
            SELECT  id, max(field1) max_field
            FROM    sometable
            GROUP   BY id
        ) b     ON a.id = b.ID AND
                    a.field1 = b.max_field

当转换为LINQ:

from a in someTable
join b in 
    (
        from o in someTable
        group o by new {o.ID} into g
        select new 
        {
          g.Key.ID,
          max_field = g.Max(p => p.field1)
        }
    ) on new {a.ID, a.field1} equals new {b.ID, field1 = b.max_field}
select a

【讨论】:

    【解决方案2】:

    您应该能够执行以下操作:

    var results = someTable
                     .GroupBy(row => row.id)
                     .Select(group => group.OrderByDescending(r => r.id).First());
    

    如果你想要第三高的值,你可以这样做:

    var results = someTable
                     .GroupBy(row => row.id)
                     .Select(group => group.OrderByDescending(r => r.id).Skip(2).FirstOrDefault())
                     .Where(r => r != null); // Remove the groups that don't have 3 items
    

    【讨论】:

    • 现在,我不想为此烦恼,但我只是好奇:如果我想要第三个或最近的项目,如果没有第三个怎么办?
    • 测试了您的解决方案,它在 SQL Server 中工作,但在 Oracle 上,生成的查询将失败,因为 Oracle 不支持“应用”。有什么想法吗?
    • @ReedCopsey 有没有办法构造这个查询以避免使用 APPLY 函数生成的 SQL?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多