LINQ to SQL с использованием GROUP BY и COUNT (DISTINCT) - PullRequest
56 голосов
/ 15 января 2009

Я должен выполнить следующий запрос SQL:

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

LINQ to SQL запрос

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

отображается на следующий запрос SQL:

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

Пока все хорошо. Однако проблема возникает при попытке группировки результатов, так как я не могу найти запрос LINQ to SQL, который сопоставляется с первым запросом, который я здесь написал (спасибо LINQPad за то, что этот процесс очень много Полегче). Следующее, единственное, что я нашел, дает мне желаемый результат:

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

Что, в свою очередь, приводит к ужасному и неоптимизированному следующему запросу 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

Любая помощь будет более чем признательна.

Ответы [ 6 ]

87 голосов
/ 16 января 2009

Прямой поддержки COUNT(DISTINCT {x})) нет, но вы можете смоделировать ее из IGrouping<,> (то есть, что group by возвращает); Боюсь, я только "делаю" C #, так что вам придется переводить на VB ...

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

Вот пример северного ветра:

    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 не совсем то, что мы хотели бы, но оно выполняет свою работу:

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

Результаты, тем не менее, можно проверить, запустив вручную:

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

С определением:

class QueryResult
{
    public string Country { get; set; }
    public int Count { get; set; }
}
10 голосов
/ 05 марта 2011

Пример Northwind, приведенный Марком Гравеллом, может быть переписан с помощью столбца 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()
};
1 голос
/ 25 декабря 2010

простой и понятный пример работы группировки по LINQ

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

1 голос
/ 16 января 2009

Это то, как вы делаете отдельный запрос подсчета. Обратите внимание, что вы должны отфильтровать нули.

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

Если вы объедините это с вашим текущим кодом группировки, я думаю, у вас будет ваше решение.

1 голос
/ 16 января 2009

Linq to sql не поддерживает Count (Distinct ...). Поэтому вы должны отобразить метод .NET в коде на функцию сервера Sql (таким образом, Count (отличный ..)) и использовать его.

Кстати, это не поможет, если вы публикуете псевдокод, скопированный из инструментария в формате, который не является ни VB.NET, ни C #.

0 голосов
/ 23 июня 2016

Я бы не стал делать это в Linq2SQL. Создайте хранимую процедуру для запроса, который вы хотите понять, а затем создайте объект для хранимой процедуры в платформе или просто подключитесь непосредственно к ней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...