2013-03-08 83 views
2

這是其他Partition By + Rank問題的可能重複,但我發現大多數這些問題/答案對其特定的業務邏輯來說過於具體。我正在尋找的是以下類型的查詢的更一般的LINQ版:我們這個做LINQ(到Oracle) - Row_Number()通過分區

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中包含最高值的行。將順序改爲asc當然會返回最低值或將等級更改爲2將獲得第二高/最低值等等。有沒有辦法編寫一個可以執行的LINQ查詢,服務器端可以給我們同樣的功能?理想情況下,像上面那樣表現良好。

編輯: 我試過很多不同的解決方案淘網在和他們都最終給我,因爲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); 

這些結果都非常相似,如果不相同,它使用一個OUTER APPLY,甲骨文不支持SQL代碼。

+0

對我來說,這似乎是一個簡單的GROUP BY'id'和'MAX(字段1)'。我錯過了什麼? – 2013-03-08 17:00:06

+0

@FrancisP在目前的形式中,是的。但是如果我不想要MAX而想要第二或第三呢?我已經刪除了這個特定部分的重點。 – Kittoes0124 2013-03-08 17:01:33

+0

@Kittoes同樣的技術應該通過增加一個「跳過」調用,然後過濾掉任何空結果... – 2013-03-08 17:04:08

回答

5

你應該能夠做一些事情,如:

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 
+0

現在,我討厭在這個屁股疼痛,但我只是好奇:如果我想要第三個或最近的項目,如果沒有第三個? – Kittoes0124 2013-03-08 17:06:27

+0

@Kittoes您可以使用'.Take(3).Last()'獲得「第三個」項目... – 2013-03-08 17:16:23

+2

測試您的解決方案,它在SQL Server中工作,但在Oracle上生成的查詢將失敗,因爲Oracle不支持「APPLY」。有任何想法嗎? – Kittoes0124 2013-03-08 17:42:28

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