为何我的GROUP BY未按预期分组?服装工厂SQL多表查询问题排查
我负责的是一家服装工厂的系统,目前涉及3张数据表:
- Person表:存储人员姓名信息;
- Category表:存储工厂的各类服装类别(如袜子sockets、鞋子shoes等);
- Inventory表:记录每位人员对应的服装数量(原描述中误写为Quantity)。
我编写了如下SQL查询语句,期望统计人员Paul各类服装的数量,并以行转列的形式展示:
SELECT Name, sum(case when category = 'shoes' then quantity else 0 end) as 'Quantity_shoes', sum(case when category = 'shirts' then quantity else 0 end) as 'Quantity_shirts', sum(case when category = 'sockets' then quantity else 0 end) as 'Quantity_shirts', sum(case when category = 'hats' then quantity else 0 end) as 'Quantity_hats' FROM person p join inventory i on i.person_id = p.id join category c c.id = i.category_id WHERE p = 'Paul' GROUP BY name, category
预期查询结果:
| Name | Quantity_shoes | Quantity_shirts | Quantity_sockets | Quantity_hats |
|---|---|---|---|---|
| Paul | 8 | 25 | 38 | 0 |
实际得到的结果:
| Name | Quantity_shoes | Quantity_shirts | Quantity_sockets | Quantity_hats |
|---|---|---|---|---|
| Paul | 8 | 0 | 0 | 0 |
| Paul | 0 | 0 | 0 | 0 |
| Paul | 0 | 25 | 0 | 0 |
| Paul | 0 | 0 | 38 | 0 |
我尝试过按quantity进行分组,但这样不仅没有实现数量求和,反而生成了更多行数据。请问我在SQL编写中哪里出现了错误?
问题分析与修正方案
你的SQL里有几个关键错误导致了多行结果,我逐一帮你梳理并修正:
GROUP BY子句逻辑错误
你当前写的GROUP BY name, category会让查询按「姓名+服装类别」进行分组,这就意味着每个类别会单独形成一行,所以每行只有对应类别的数量有值,其他列自然都是0。要实现行转列的合并效果,你只需要按Name(或者更严谨的p.id,避免重名问题)分组即可,完全不需要包含category。JOIN语法遗漏关键字
关联Category表时,你漏写了ON关键字,正确的写法应该是join category c on c.id = i.category_id——虽然部分数据库可能兼容错误语法,但这属于不规范写法,会埋下隐患。列别名笔误
统计袜子(sockets)的列别名写错了,你写成了Quantity_shirts,应该改成Quantity_sockets,否则会和衬衫的列重名,导致结果展示混乱。WHERE子句条件错误
WHERE p = 'Paul'是错误的,你需要指定具体的列名,应该写成WHERE p.Name = 'Paul'——p是Person表的别名,不能直接和字符串做比较。
修正后的SQL
SELECT p.Name, SUM(CASE WHEN c.category = 'shoes' THEN i.quantity ELSE 0 END) AS Quantity_shoes, SUM(CASE WHEN c.category = 'shirts' THEN i.quantity ELSE 0 END) AS Quantity_shirts, SUM(CASE WHEN c.category = 'sockets' THEN i.quantity ELSE 0 END) AS Quantity_sockets, SUM(CASE WHEN c.category = 'hats' THEN i.quantity ELSE 0 END) AS Quantity_hats FROM person p JOIN inventory i ON i.person_id = p.id JOIN category c ON c.id = i.category_id WHERE p.Name = 'Paul' GROUP BY p.Name; -- 用p.id分组会更严谨,避免姓名重复的情况
为什么这样改能解决问题?
去掉category分组后,SUM()函数会把Paul的所有库存记录中符合CASE条件的值累加起来,每个服装类别的总数量就会被计算到对应的列中,最终合并成一行展示,正好符合你的预期结果。
内容的提问来源于stack exchange,提问作者Louis Chopard

