LINQ在多个列上进行COUNT操作

7

如果我有一个带有标题列和3个位列(f1、f2、f3)的表,其中包含1或NULL,我该如何编写LINQ以返回标题及包含1的每个位列的计数? 我正在寻找此SQL查询的等效项:

SELECT title, COUNT(f1), COUNT(f2), COUNT(f3) FROM myTable GROUP BY title

我正在寻找最佳的方法来解决这个问题。根据底层的SQL查询,我想到的版本需要4次访问表格,所以速度太慢。

3个回答

4

如果您想坚持使用LINQ查询并使用匿名类型,查询可能如下所示:

 var query = 
      from r in ctx.myTable
      group r by r.title into rgroup
      select new
      {
          Title = rgroup.Key,
          F1Count = rgroup.Count(rg => rg.f1 == true),
          F2Count = rgroup.Count(rg => rg.f2 == true),
          F3Count = rgroup.Count(rg => rg.f3 == true)
      };

诀窍在于要识别出您想要计算真实字段的数量(它被映射为可为空的布尔值),这可以通过Count运算符和谓词来实现。有关LINQ组操作符的更多信息,请参见标准LINQ操作符


3
这是我最初想出的解决方案,但生成的查询使用子查询来产生每个单独的计数。在一个没有索引的具有50万行的表上,这个版本需要7秒钟,而用3个COUNT的正确SQL则是即时的。 - gfrizzle

2

我认为这就是LINQ的局限性。如果你想要高效,使用SQL;如果你想要优美的代码,使用LINQ。

既然你已经知道了SQL,你也可以直接执行查询。

class TitleCount {
    public string Title;
    public int Count1;
    public int Count2;
    public int Count3;
}

DataContext dc = new DataContext("Connection string to db");

IEnumerable<TitleCount> query = dc.ExecuteQuery<TitleCount>(
    @"SELECT title, 
             COUNT(f1) as Count1, 
             COUNT(f2) as Count2, 
             COUNT(f3) as Count3 
       FROM myTable GROUP BY title");

0
这是我想出的解决方案。请注意,它与@OdeToCode提出的解决方案非常接近(但使用VB语法),有一个主要区别:
Dim temp = _
    (From t In context.MyTable _
     Group t.f1, t.f2, t.f3 By t.title Into g = Group _
     Select title, g).ToList

Dim results = _
    From t In temp _
    Select t.title, _
        f1_count = t.g.Count(Function(x) If(x.f1, False)), _
        f2_count = t.g.Count(Function(x) If(x.f2, False)), _
        f3_count = t.g.Count(Function(x) If(x.f3, False))

第一个查询进行分组,但ToList从服务器获取分组数据。在此处消除计数可以使生成子SELECT的结果SQL语句不产生。我在第二个查询中本地进行计数。
这样做是因为我知道第一个查询将返回可管理的行数。如果它返回数百万行,我可能需要采用其他方法。

2
不要用于大型数据集!请不要将此复制粘贴到您的应用程序中。这个答案应该有一个巨大的警告。 - Rush Frisby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接