2010-11-27 74 views
6

我有一個數據庫表,每行都包含一個順序索引。我想根據此索引列選擇連續的行組。舉例來說,如果我有以下指標值的行:選擇LINQ to Entities的連續條目

1 
3 
4 
5 
7 
9 
10 
11 
12 
15 
16 

,我想選擇具有連續的3個指標(這個數字會有所不同),所有組。我會得到以下幾組:

3, 4, 5 

9, 10, 11 

10, 11, 12 

基本上,我試圖實現類似的問題所造成的東西在這裏:

selecting consecutive numbers using SQL query

不過,我想使用LINQ來實現這實體,而不是實際的SQL。我也不想使用存儲過程,我不想做任何形式的ToList /循環方法。

編輯:具有多於請求的連續元素的組不一定需要分開。即在前面的例子中,9,10,11,12的結果也是可接受的。

回答

0
using (var model = new AlbinTestEntities()) 
{ 
    var triples = from t1 in model.Numbers 
        from t2 in model.Numbers 
        from t3 in model.Numbers 
        where t1.Number + 1 == t2.Number 
        where t2.Number + 1 == t3.Number 
        select new 
        { 
         t1 = t1.Number, 
         t2 = t2.Number, 
         t3 = t3.Number, 
        }; 

    foreach (var res in triples) 
    { 
     Console.WriteLine(res.t1 + ", " + res.t2 + ", " + res.t3); 
    } 
} 

生成下面的SQL

SELECT 
[Extent1].[Number] AS [Number], 
[Extent2].[Number] AS [Number1], 
[Extent3].[Number] AS [Number2] 
FROM [dbo].[Numbers] AS [Extent1] 
CROSS JOIN [dbo].[Numbers] AS [Extent2] 
CROSS JOIN [dbo].[Numbers] AS [Extent3] 
WHERE (([Extent1].[Number] + 1) = [Extent2].[Number]) AND (([Extent2].[Number] + 1) = [Extent3].[Number]) 

這可能是更好的使用內部連接這樣

using (var model = new AlbinTestEntities()) 
{ 
    var triples = from t1 in model.Numbers 
        join t2 in model.Numbers on t1.Number + 1 equals t2.Number 
        join t3 in model.Numbers on t2.Number + 1 equals t3.Number 
        select new 
        { 
         t1 = t1.Number, 
         t2 = t2.Number, 
         t3 = t3.Number, 
        }; 

    foreach (var res in triples) 
    { 
     Console.WriteLine(res.t1 + ", " + res.t2 + ", " + res.t3); 
    } 
} 

,但是當我在Management Studio中比較所產生的疑問,他們產生執行計劃相同,執行時間也完全相同。我只有這個有限的數據集,如果數據集較大,可以比較數據集的性能,如果它們不同,則選擇最佳數據集。

+0

感謝您的答覆。但是,這看起來只能用於3行。我需要的數字有所不同;我可能需要連續2行,或者我可能需要20行。有沒有辦法實現這一點? – knoia 2010-11-27 22:11:56

0

以下代碼將查找每個「根」。

var query = this.commercialRepository.GetQuery(); 
    var count = 2; 
    for (int i = 0; i < count; i++) 
    { 
     query = query.Join(query, outer => outer.Index + 1, inner => inner.Index, (outer, inner) => outer); 
    } 

    var dummy = query.ToList(); 

它只會找到每個組中的第一個項目,所以你將不得不修改查詢到remeber其他的人或者你可以基於這樣的事實,你有根和進行查詢來自於你知道要獲得哪些索引。對不起,在我不得不離開之前我不能把它包裝起來,但也許它有點幫助。

PS。如果計數是2,就像在這種情況下一樣,這意味着如果找到3組。3

+0

這看起來像它會工作。但是我還有一個關於這種方法的擔憂:做這麼多連接會對性能造成影響嗎?在主題中,我鏈接到頂級答案似乎只做一個連接。 – knoia 2010-11-27 22:42:58

+0

我測試了這個計數爲6並且約有130個連接。 – knoia 2010-11-28 01:48:45

1

所以我想我已經提出了一個很好的解決方案,模仿Brian的主題I鏈接到的答案。

var q = from a in query 
     from b in query 
     where a.Index < b.Index 
     && b.Index < a.Index + 3 
     group b by new { a.Index } 
      into myGroup 
      where myGroup.Count() + 1 == 3 
      select myGroup.Key.Index; 

將3更改爲所需的連續行數。這爲您提供了每組連續行的第一個索引。適用於我所提供的原來的例子,你會得到:

3 
9 
10 
1

我想這可能工作很有效(C#雖然):

int[] query = { 1, 3, 4, 5, 7, 9, 10, 11, 12, 15, 16 }; 
int count = 3; 
List<List<int>> numbers = query 
    .Where(p => query.Where(q => q >= p && q < p + count).Count() == count) 
    .Select(p => Enumerable.Range(p, count).ToList()) 
    .ToList();