c# - sintaxis - LINQ to SQL usando GROUP BY y COUNT(DISTINCT)
obtener resultado consulta sql c# (6)
Tengo que realizar la siguiente consulta SQL:
select answer_nbr, count(distinct user_nbr)
from tpoll_answer
where poll_nbr = 16
group by answer_nbr
La consulta LINQ a SQL
from a in tpoll_answer
where a.poll_nbr = 16 select a.answer_nbr, a.user_nbr distinct
mapas a la siguiente consulta SQL:
select distinct answer_nbr, distinct user_nbr
from tpoll_answer
where poll_nbr = 16
Hasta aquí todo bien. Sin embargo, el problema surge cuando intento agrupar los resultados, ya que no puedo encontrar una consulta de LINQ a SQL que coincida con la primera consulta que escribí aquí (gracias LINQPad por facilitar mucho este proceso). El siguiente es el único que encontré que me da el resultado deseado:
from answer in tpoll_answer where answer.poll_nbr = 16 _
group by a_id = answer.answer_nbr into votes = count(answer.user_nbr)
Que a su vez produce el siguiente feo y no optimizado en todas las consultas 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
Cualquier ayuda será más que apreciada.
Así es como haces una consulta de recuento distinta. Tenga en cuenta que debe filtrar los nulos.
var useranswercount = (from a in tpoll_answer
where user_nbr != null && answer_nbr != null
select user_nbr).Distinct().Count();
Si combina esto con su código de agrupación actual, creo que tendrá su solución.
El ejemplo de Northwind citado por Marc Gravell se puede reescribir con la columna Ciudad seleccionada directamente por la declaración del grupo:
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 no tiene soporte para Count (Distinct ...). Por lo tanto, tiene que asignar un método .NET en el código a una función de servidor Sql (así Count (distinct ..)) y usar eso.
Por cierto, no ayuda si publica un pseudo código copiado de un kit de herramientas en un formato que no es ni VB.NET ni C #.
No hay soporte directo para COUNT(DISTINCT {x}))
, pero puede simularlo desde un IGrouping<,>
(es decir, qué group by
devuelve); Me temo que solo "hago" C #, así que tendrás que traducir a VB ...
select new
{
Foo= grp.Key,
Bar= grp.Select(x => x.SomeField).Distinct().Count()
};
Aquí hay un ejemplo de 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);
}
}
El TSQL no es exactamente lo que nos gustaría, pero cumple su función:
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
Los resultados, sin embargo, son correctos, verificables al ejecutarlo manualmente:
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);
}
Con definición:
class QueryResult
{
public string Country { get; set; }
public int Count { get; set; }
}
No me molestaría en hacerlo en Linq2SQL. Cree un Procedimiento almacenado para la consulta que desea y entiende y luego cree el objeto para el procedimiento almacenado en el marco o simplemente conéctese directamente.
ejemplo simple y limpio de cómo el grupo trabaja en LINQ
http://www.a2zmenu.com/LINQ/LINQ-to-SQL-Group-By-Operator.aspx