Преобразовать подзапрос SQL в In в Linq Lambda - PullRequest
3 голосов
/ 03 апреля 2011

Как преобразовать следующий оператор SQL в лямбда-выражение или запрос Linq?

Следующий запрос получает самый последний ответ на каждый вопрос. Или, чтобы сформулировать это по-другому, получите каждый вопрос с самым новым ответом.

Также это будет выполняться Entity Framework.

SELECT Answers.*
FROM Answers
Where AnswerID IN
(
    SELECT Max(AnswerID) AnswerID
    FROM Answers
    GROUP BY QuestionID
)

Вот еще один способ посмотреть на предыдущий запрос, используя Inner Join

SELECT answers.* 
FROM answers 
INNER JOIN  
(
     SELECT Max(answerID) answerID --,  QuestionSiteID
     FROM answers
     GROUP BY QuestionID 
) t ON
     answers.answerID = t.answerID  

Я прочитал, что метод LINQ Contains неоптимален для запросов, обращающихся к SQL.
LINQ to Sql и ловушка .Contains ().

Ответы [ 3 ]

5 голосов
/ 03 апреля 2011

Я думаю, вы могли бы сделать это, используя что-то вроде:

 var subQuery = from a in answers
                group a by a.QuestionID into grouping
                select new
                {
                    QuestionID = grouping.Key,
                    MaxAnswerID = grouping.Max(x => x.AnswerID)
                };

 var query = from a in answers
             from s in subQuery
             where a.AnswerID == s.MaxAnswerID
             select a;

Это приводит к CROSS JOIN в сгенерированном SQL


Также вы можете использовать join во второй части запроса:

 var query = from a in answers
             join s in subQuery on a.AnswerID equals s.MaxAnswerID
             select a;

Это приводит к ВНУТРЕННЕМУ СОЕДИНЕНИЮ в SQL


Примечание для дополнительных случаев - приведенные выше ответы дают разумное предположение о том, что AnswerID является первичным ключом Answers - если у вас вместо этого есть план таблицы, в котором используется ключ (AnswerID, QuestionID), тогда вам потребуется присоединиться как по AnswerID, так и QuestionID, например:

 var subQuery = from a in answers
                group a by a.QuestionID into grouping
                select new
                {
                    QuestionID = grouping.Key,
                    MaxAnswerID = grouping.Max(x => x.AnswerID)
                };

 var query = from a in answers
             from s in subQuery
             where a.AnswerID == s.MaxAnswerID
             && a.QuestionID == s.QuestionID
             select a;

См. Комментарий к дальнейшему обсуждению этого альтернативного дизайна таблицы ...

2 голосов
/ 03 апреля 2011

Вы можете использовать оператор let для выбора первого ответа для группы QuestionID:

from answer in Answers
group answer by answer.QuestionID into question
let firstAnswer = question.OrderByDescending(q => q.AnswerID).First()
select firstAnswer

РЕДАКТИРОВАТЬ: Linq2Sql преобразует вышеуказанный запрос в вызовы базы данных N + 1.Этот запрос переводится только на один SQL-запрос:

from a in Answers
group a by a.QuestionID into grouping
join a2 in Answers on 
    new {AnswerID = grouping.Max(x => x.AnswerID), QuestionID = grouping.Key} 
    equals new {a2.AnswerID, a2.QuestionID}
select a2

Меня удивляет, каким образом Linq2Sql должен быть проще, чем SQL.

0 голосов
/ 03 апреля 2011

Попробуйте использовать этот запрос:

var query = from c in context.Childs
            group c by c.ParentEntityId into pc
            select pc.OrderByDescending(pcc => pcc.Id).Take(1);

Я только что проверил запрос в профилировщике, и он выдает один SQL-запрос (уродливый):

SELECT 
[Project3].[ParentEntityId] AS [ParentEntityId], 
[Project3].[C1] AS [C1], 
[Project3].[Id] AS [Id], 
[Project3].[Name] AS [Name], 
[Project3].[ParentEntityId1] AS [ParentEntityId1]
FROM ( SELECT 
    [Distinct1].[ParentEntityId] AS [ParentEntityId], 
    [Limit1].[Id] AS [Id], 
    [Limit1].[Name] AS [Name], 
    [Limit1].[ParentEntityId] AS [ParentEntityId1], 
    CASE WHEN ([Limit1].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT DISTINCT 
        [Extent1].[ParentEntityId] AS [ParentEntityId]
        FROM [dbo].[ChildEntities] AS [Extent1] ) AS [Distinct1]
    OUTER APPLY  (SELECT TOP (1) [Project2].[Id] AS [Id], [Project2].[Name] AS [Name], [Project2].[ParentEntityId] AS [ParentEntityId]
        FROM ( SELECT 
            [Extent2].[Id] AS [Id], 
            [Extent2].[Name] AS [Name], 
            [Extent2].[ParentEntityId] AS [ParentEntityId]
            FROM [dbo].[ChildEntities] AS [Extent2]
            WHERE ([Distinct1].[ParentEntityId] = [Extent2].[ParentEntityId]) OR (([Distinct1].[ParentEntityId] IS NULL) AND ([Extent2].[ParentEntityId] IS NULL))
        )  AS [Project2]
        ORDER BY [Project2].[Id] DESC ) AS [Limit1]
)  AS [Project3]
ORDER BY [Project3].[ParentEntityId] ASC, [Project3].[C1] ASC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...