简体   繁体   English

使用GROUP BY和COUNT(DISTINCT)的LINQ to SQL

[英]LINQ to SQL using GROUP BY and COUNT(DISTINCT)

I have to perform the following SQL query: 我必须执行以下SQL查询:

select answer_nbr, count(distinct user_nbr)
from tpoll_answer
where poll_nbr = 16
group by answer_nbr

The LINQ to SQL query LINQ to SQL查询

from a in tpoll_answer 
where a.poll_nbr = 16 select a.answer_nbr, a.user_nbr distinct 

maps to the following SQL query: 映射到以下SQL查询:

select distinct answer_nbr, distinct user_nbr
from tpoll_answer
where poll_nbr = 16

So far, so good. 到现在为止还挺好。 However the problem raises when trying to GROUP the results, as I'm not being able to find a LINQ to SQL query that maps to the first query I wrote here (thank you LINQPad for making this process a lot easier). 但是当尝试GROUP结果时问题就出现了,因为我无法找到映射到我在这里写的第一个查询的LINQ to SQL查询(感谢LINQPad让这个过程变得更容易)。 The following is the only one that I've found that gives me the desired result: 以下是我发现的唯一一个给我预期结果的:

from answer in tpoll_answer where answer.poll_nbr = 16 _
group by a_id = answer.answer_nbr into votes = count(answer.user_nbr)

Which in turns produces the follwing ugly and non-optimized at all SQL query: 这反过来会产生所有SQL查询中的丑陋和非优化:

SELECT [t1].[answer_nbr] AS [a_id], (
    SELECT COUNT(*)
    FROM (
        SELECT CONVERT(Bit,[t2].[user_nbr]) AS [value], [t2].[answer_nbr], [t2].[poll_nbr]
        FROM [TPOLL_ANSWER] AS [t2]
        ) AS [t3]
    WHERE ([t3].[value] = 1) AND ([t1].[answer_nbr] = [t3].[answer_nbr]) AND ([t3].[poll_nbr] = @p0)
    ) AS [votes]
FROM (
    SELECT [t0].[answer_nbr]
    FROM [TPOLL_ANSWER] AS [t0]
    WHERE [t0].[poll_nbr] = @p0
    GROUP BY [t0].[answer_nbr]
    ) AS [t1]
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [16]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1

Any help will be more than appreciated. 任何帮助将不仅仅是赞赏。

There isn't direct support for COUNT(DISTINCT {x})) , but you can simulate it from an IGrouping<,> (ie what group by returns); 没有直接支持COUNT(DISTINCT {x})) ,但你可以从IGrouping<,>模拟它(即返回什么group by ); I'm afraid I only "do" C#, so you'll have to translate to VB... 我担心我只会“做”C#,所以你必须翻译成VB ...

 select new
 {
     Foo= grp.Key,
     Bar= grp.Select(x => x.SomeField).Distinct().Count()
 };

Here's a Northwind example: 这是一个Northwind示例:

    using(var ctx = new DataClasses1DataContext())
    {
        ctx.Log = Console.Out; // log TSQL to console
        var qry = from cust in ctx.Customers
                  where cust.CustomerID != ""
                  group cust by cust.Country
                  into grp
                  select new
                  {
                      Country = grp.Key,
                      Count = grp.Select(x => x.City).Distinct().Count()
                  };

        foreach(var row in qry.OrderBy(x=>x.Country))
        {
            Console.WriteLine("{0}: {1}", row.Country, row.Count);
        }
    }

The TSQL isn't quite what we'd like, but it does the job: TSQL不是我们想要的,但是它完成了这项工作:

SELECT [t1].[Country], (
    SELECT COUNT(*)
    FROM (
        SELECT DISTINCT [t2].[City]
        FROM [dbo].[Customers] AS [t2]
        WHERE ((([t1].[Country] IS NULL) AND ([t2].[Country] IS NULL)) OR (([t1]
.[Country] IS NOT NULL) AND ([t2].[Country] IS NOT NULL) AND ([t1].[Country] = [
t2].[Country]))) AND ([t2].[CustomerID] <> @p0)
        ) AS [t3]
    ) AS [Count]
FROM (
    SELECT [t0].[Country]
    FROM [dbo].[Customers] AS [t0]
    WHERE [t0].[CustomerID] <> @p0
    GROUP BY [t0].[Country]
    ) AS [t1]
-- @p0: Input NVarChar (Size = 0; Prec = 0; Scale = 0) []
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1

The results, however, are correct- verifyable by running it manually: 但是,通过手动运行结果可以正确验证结果:

        const string sql = @"
SELECT c.Country, COUNT(DISTINCT c.City) AS [Count]
FROM Customers c
WHERE c.CustomerID != ''
GROUP BY c.Country
ORDER BY c.Country";
        var qry2 = ctx.ExecuteQuery<QueryResult>(sql);
        foreach(var row in qry2)
        {
            Console.WriteLine("{0}: {1}", row.Country, row.Count);
        }

With definition: 定义:

class QueryResult
{
    public string Country { get; set; }
    public int Count { get; set; }
}

The Northwind example cited by Marc Gravell can be rewritten with the City column selected directly by the group statement: Marc Gravell引用的Northwind示例可以使用group语句直接选择的City列重写:

from cust in ctx.Customers
where cust.CustomerID != ""
group cust.City /*here*/ by cust.Country
into grp
select new
{
        Country = grp.Key,
        Count = grp.Distinct().Count()
};

Linq to sql has no support for Count(Distinct ...). Linq to sql不支持Count(Distinct ...)。 You therefore have to map a .NET method in code onto a Sql server function (thus Count(distinct.. )) and use that. 因此,您必须将代码中的.NET方法映射到Sql服务器函数(因此为Count(distinct ..))并使用它。

btw, it doesn't help if you post pseudo code copied from a toolkit in a format that's neither VB.NET nor C#. 顺便说一句,如果你发布从工具箱中复制的伪代码,它既不是VB.NET也不是C#的格式也无济于事。

This is how you do a distinct count query. 这是您执行非常计数查询的方式。 Note that you have to filter out the nulls. 请注意,您必须过滤掉空值。

var useranswercount = (from a in tpoll_answer
where user_nbr != null && answer_nbr != null
select user_nbr).Distinct().Count();

If you combine this with into your current grouping code, I think you'll have your solution. 如果将此与您当前的分组代码结合使用,我认为您将拥有自己的解决方案。

simple and clean example of how group by works in LINQ LINQ中group by如何工作的简单而干净的例子

http://www.a2zmenu.com/LINQ/LINQ-to-SQL-Group-By-Operator.aspx http://www.a2zmenu.com/LINQ/LINQ-to-SQL-Group-By-Operator.aspx

I wouldn't bother doing it in Linq2SQL. 我不打算在Linq2SQL中做这件事。 Create a stored Procedure for the query you want and understand and then create the object to the stored procedure in the framework or just connect direct to it. 为您想要和理解的查询创建存储过程,然后在框架中创建存储过程的对象,或者直接连接到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM