LINQ to SQL using GROUP BY and COUNT (DISTINCT)

I need to execute the following SQL query:

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

LINQ to SQL Query

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

displays the following SQL query:

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

So far so good. However, the problem arises when trying GROUP for the results, because I cannot find the LINQ to SQL query that maps to the first query I wrote here (thanks LINQPad to make this process much easier). The only thing I found is the following:

 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 turn produces the following ugly and not optimized in all SQL queries:

 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 would be more than appreciated.

+52
c # linq linq-to-sql
Jan 15 '09 at 19:51
source share
6 answers

There is direct support for COUNT(DISTINCT {x})) , but you can imitate it from IGrouping<,> (that is, what group by returns); I'm afraid that I am only β€œdoing” C #, so you have to translate to VB ...

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

Here's an example of 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); } } 

TSQL is not exactly what we would like, but it does the job:

 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 correctly verified 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 the definition of:

 class QueryResult { public string Country { get; set; } public int Count { get; set; } } 
+78
Jan 16 '09 at 9:42
source share

The Northwind example provided by Mark Gravell can be rewritten using the City column selected directly in the group statement:

 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() }; 
+10
Mar 04 2018-11-11T00:
source share

Linq to sql does not support Count (Distinct ...). Therefore, you need to map the .NET method in the code to the server-side Sql function (thus, Count (reporting)) and use this.

btw, this will not help if you publish pseudocode copied from the toolkit in a format that neither VB.NET nor C #.

+1
Jan 16 '09 at 8:31
source share

This is how you make a separate counter request. Note that you need to filter zeros.

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

If you combine this with your current grouping code, I think you will have your solution.

+1
Jan 16 '09 at 8:58
source share

a simple and clean example of how a group works in LINQ

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

+1
Dec 25 '10 at 11:09
source share

I would not do it in Linq2SQL. Create a stored procedure for the query that you want and understand, and then create an object for the stored procedure in the framework, or simply connect to it directly.

-four
Jun 23 '16 at 15:01
source share



All Articles