分组合并行

分组聚合:将一对多关联结果合并到一行

问题回顾

在上一节的左连接示例中,ProductName 无法直接显示出来,原因是一个学生可能对应多个产品。分组后如果直接 select,每条匹配记录都会单独成行,无法将多个产品合并展示。

核心思路:​ 对未分组的行进行聚合合并,把同一个学生的所有产品信息压缩到一行中显示。


LINQ 实现代码

static void Main(string[] args)
{
    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
                    let productNames = g.Select(m => m.p.Name + ":" + m.p.Price)
                    select new
                    {
                        g.Key.ID,
                        g.Key.Name,
                        info = string.Join(",", productNames)
                    };

        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 和姓名分组,将同一学生的所有 {学生, 产品} 组合归入组 g
③ 投影let productNames = g.Select(m => m.p.Name + ":" + m.p.Price)从每组中提取产品信息,格式为 "产品名:价格"
④ 聚合info = string.Join(",", productNames)将当前学生的所有产品字符串用逗号拼接成一个字符串

执行逻辑示意

原始匹配结果(多行):
┌──────┬──────────┬───────┐
│ 学生 │ 产品名   │ 价格  │
├──────┼──────────┼───────┤
│ 张三 │ 沙发     │ 999   │
│ 张三 │ 跑步机   │ 888   │
│ 李四 │ 哑铃     │ 299   │
└──────┴──────────┴───────┘

分组聚合后(一行一学生):
┌──────┬──────────────────────────────┐
│ 学生 │ info                         │
├──────┼──────────────────────────────┤
│ 张三 │ 沙发:999,跑步机:888          │
│ 李四 │ 哑铃:299                     │
└──────┴──────────────────────────────┘Code language: CSS (css)

关键语法点

  • group … by … into g:将连接后的扁平结果按指定键重新分组,每组内可访问该学生的所有匹配行
  • let:定义中间变量,避免在 select 中重复书写复杂表达式
  • string.Join():将集合中的元素拼接为单个字符串,是实现”多行合一”的核心方法

与左连接的对比

场景上一节(左连接)本节(分组聚合)
连接方式join … into + DefaultIfEmpty()直接 join
未匹配学生显示,右表字段为 null不显示(内连接特性)
匹配学生每个学生多条记录每个学生仅一行
产品展示逐行列出合并为一个字符串

如果需要保留未匹配学生,同时合并产品信息,可以将两种方式结合:先左连接,再分组聚合。

发表回复

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