分组后进行过滤having的使用

对 Group By 后的结果进行过滤(HAVING 等效)

SQL 中的 HAVING

在 SQL 中,可以使用 HAVINGGROUP BY 后的聚合结果进行进一步过滤:

SELECT ID, Name, AVG(Price) FROM
(
    SELECT s.ID, s.Name, p.Name AS ProductName, p.Price
    FROM Student s
    INNER JOIN Product AS p
    ON s.ID = p.Sid
) AS t
GROUP BY ID, Name
HAVING ID = 2Code language: PHP (php)

LINQ 中的对应写法

在 LINQ 中,没有 HAVING 关键字。不管是过滤 SELECT 的原始行,还是过滤 GROUP BY 后的分组结果,统一使用 where

using (var db = new DataClasses1DataContext())
{
    var query = from s in db.Student
                join p in db.Product
                on s.ID equals p.Sid
                group new { s, p } by new { s.ID, s.Name } into g
                where g.Key.ID == 1
                select new
                {
                    g.Key.ID,
                    g.Key.Name,
                    sum = g.Sum(m => m.p.Price)
                };

    var result = query.ToList();
}Code language: JavaScript (javascript)

执行逻辑解析

步骤代码说明
① 连接join p in db.Product on s.ID equals p.Sid学生表与产品表内连接
② 分组group new { s, p } by new { s.ID, s.Name } into g按学生 ID 和姓名分组
③ 过滤where g.Key.ID == 1对分组结果进行过滤(等效 SQL 的 HAVING
④ 投影select new { g.Key.ID, g.Key.Name, sum = g.Sum(m => m.p.Price) }取分组键字段,并对组内价格求和

SQL 生成对照

上述 LINQ 最终生成的 SQL 等价于:

SELECT s.ID, s.Name, SUM(p.Price) AS sum
FROM Student s
INNER JOIN Product p ON s.ID = p.Sid
GROUP BY s.ID, s.Name
HAVING s.ID = 1Code language: PHP (php)

关键要点

  • where 的位置决定语义:​ 写在 group by 之前where 等效于 SQL 的 WHERE(分组前过滤行);写在 group by ... into g 之后where 等效于 SQL 的 HAVING(分组后过滤组)
  • 分组后过滤的写法:where g.Key.ID == 1 中的 g.Key 对应 SQL 中 GROUP BY 的键列
  • 聚合后过滤:​ 如果要根据聚合函数结果过滤(如 SUM > 1000),写法为 where g.Sum(m => m.p.Price) > 1000

分组前过滤 vs 分组后过滤对比

// 分组前过滤(等效 WHERE)—— 先过滤行,再分组
var query1 = from s in db.Student
             join p in db.Product on s.ID equals p.Sid
             where s.ID == 1
             group new { s, p } by new { s.ID, s.Name } into g
             select new { g.Key.ID, g.Key.Name, sum = g.Sum(m => m.p.Price) };

// 分组后过滤(等效 HAVING)—— 先分组,再过滤组
var query2 = from s in db.Student
             join p in db.Product on s.ID equals p.Sid
             group new { s, p } by new { s.ID, s.Name } into g
             where g.Key.ID == 1
             select new { g.Key.ID, g.Key.Name, sum = g.Sum(m => m.p.Price) };Code language: JavaScript (javascript)

两种写法生成的 SQL 不同:前者将条件置于 GROUP BY 之前,后者置于 HAVING 子句中。在索引利用和性能上可能有所差异,需根据实际数据分布选择。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注