【问题标题】:Selecting Consecutive Entries with LINQ to Entities使用 LINQ to Entities 选择连续条目
【发布时间】:2010-11-27 20:50:20
【问题描述】:

我有一个数据库表,其中每行都包含一个顺序索引。我想根据此索引列选择连续的行组。例如,如果我有具有以下索引值的行:

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 to Entities 来实现这一点,而不是实际的 SQL。我也不想使用存储过程,也不想做任何类型的 ToList/循环方法。

编辑:具有超过请求的连续元素的组不一定需要分开。即在前面的示例中,9、10、11、12 的结果也是可以接受的。

【问题讨论】:

    标签: database linq linq-to-entities


    【解决方案1】:

    所以我想我已经想出了一个很好的解决方案,模仿了 Brian 在我链接到的主题中的回答。

    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
    

    【讨论】:

      【解决方案2】:

      我认为这可能会非常有效(虽然是 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();
      

      【讨论】:

      • 这应该适用于 Linq to Objects,但不适用于 Linq to Entities。
      【解决方案3】:
      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 中比较生成的查询时,它们会生成相同的执行计划并花费完全相同的时间来执行。我只有这个有限的数据集,如果数据集较大,您可以比较数据集的性能,如果它们不同,则选择最好的。

      【讨论】:

      • 感谢您的回复。但是,这看起来只适用于 3 行。我需要改变数字;我可能需要 2 个连续的行,或者我可能需要 20 个。有没有办法做到这一点?
      【解决方案4】:

      以下代码将找到每个“根”。

          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();
      

      它只会找到每个组中的第一项,因此您必须修改查询以记住其他项,或者您可以根据您有根以及您知道哪些索引的事实进行查询得到。很抱歉,在我不得不离开之前我无法把它包起来,但也许它会有所帮助。

      附言。如果 count 为 2,在这种情况下,这意味着如果找到 3 个组。

      【讨论】:

      • 这看起来可行。但是我对这种方法还有另一个担忧:做这么多的连接会对性能不利吗?在我链接到最佳答案的主题中,似乎只进行了一次连接。
      • 我用 6 个计数对此进行了测试,最终得到了大约 130 个连接。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      相关资源
      最近更新 更多