我有学生表,我想写一个Linq查询来获取多个计数。 Linq生成的SQL查询过于复杂且未经优化。
以下是我的表的定义:
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
[Age] [int] NULL,
我需要给名字=考试的学生一个计数,并为年龄> gt的学生计算一个计数; 10。 这是我试过的一个查询:
var sql = from st in school.Students
group st by 1 into grp
select new
{
NameCount = grp.Count(k => k.Name == "Test"),
AgeCount = grp.Count(k => k.Age > 5)
};
生成的SQL查询是:
SELECT
[Limit1].[C1] AS [C1],
[Limit1].[C2] AS [C2],
[Limit1].[C3] AS [C3]
FROM ( SELECT TOP (1)
[Project2].[C1] AS [C1],
[Project2].[C2] AS [C2],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Student] AS [Extent3]
WHERE ([Project2].[C1] = 1) AND ([Extent3].[Age] > 5)) AS [C3]
FROM ( SELECT
[Distinct1].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[Student] AS [Extent2]
WHERE ([Distinct1].[C1] = 1) AND (N'Test' = [Extent2].[Name])) AS [C2]
FROM ( SELECT DISTINCT
1 AS [C1]
FROM [dbo].[Student] AS [Extent1]
) AS [Distinct1]
) AS [Project2]
) AS [Limit1]
对我而言,这似乎很复杂。这可以通过以下简单查询来实现:
select COUNT(CASE WHEN st.Name = 'Test' THEN 1 ELSE 0 END) NameCount,
COUNT(CASE WHEN st.Age > 5 THEN 1 ELSE 0 END) AgeCount from Student st
LINQ中是否有一种方法可以将生成的SQL查询同时具有聚合而不是将两个单独的查询与嵌套查询相结合?
答案 0 :(得分:5)
根据我使用EF6的经验,条件Sum
(即Sum(condition ? 1 : 0)
)的翻译效果要比使用谓词Count
的{{1}}更好地转换为SQL:
Count(condition)
顺便说一下,你的SQL示例也应该使用var query =
from st in school.Students
group st by 1 into grp
select new
{
NameCount = grp.Sum(k => k.Name == "Test" ? 1 : 0),
AgeCount = grp.Sum(k => k.Age > 5 ? 1 : 0)
};
。为了利用排除SUM
s的SQL COUNT
,它应该是NULL
或者不是ELSE NULL
:
ELSE
但是没有相应的LINQ构造,因此没有办法让EF6生成这样的翻译。但IMO select COUNT(CASE WHEN st.Name = 'Test' THEN 1 END) NameCount,
COUNT(CASE WHEN st.Age > 5 THEN 1 END) AgeCount
from Student st
足够相当。
答案 1 :(得分:0)
更简单的查询是因为没有使用不必要的组,只是在select
中查询了两次表:
var sql = from st in school.Students.Take(1)
select new {
NameCount = school.Students.Count(k => k.Name == "Test"),
AgeCount = school.Students.Count(k => k.Age > 5)
};