SQL报错解析:子查询未用EXISTS时SELECT限制及多表统计需求
报错信息
当子查询未使用EXISTS引入且包含多个查询时,SELECT列表中只能指定一个表达式。
数据源表
表1
| StudentId | StuName | 已缴学校费用 |
|---|---|---|
| 1 | s1 | 10000 |
| 2 | s2 | 40000 |
| 3 | s1 | 20000 |
| 4 | s4 | 10000 |
| 30,22,48,60 | s6,s8,s9,s10 | 3300 |
| 8 | s12 | 1200 |
| 10 | s4 | 5000 |
| 12 | s16 | 4000 |
| 18,16 | s20,s21 | 10000 |
| 20 | s2 | 40000 |
| 22 | s6 | 30000 |
表2
| StudentId | StuName | 已缴学费 |
|---|---|---|
| 66 | s66 | 10000 |
| 27 | s27 | 40000 |
| 3 | s3 | 20000 |
| 54 | s4 | 10000 |
| 30,22,48,60 | s6,s8,s9,s10 | 3300 |
| 8 | s12 | 1200 |
| 40 | s14 | 5000 |
| 12 | s16 | 4000 |
| 18,16 | s20,s21 | 10000 |
| 20 | s20 | 40000 |
| 25 | s25 | 30000 |
预期输出
| 已缴学校费用 | 已缴学费 | Count3 | Count4 | |
|---|---|---|---|---|
| Student1 | 10000 | 7000 | 4 | 2 |
| Student2 | 40000 | 10000 | 3 | 5 |
| Student3 | 70000 | 6000 | 4 | 3 |
| Student4 | 80000 | 4000 | 2 | 1 |
| Student5 | 5000 | 9000 | 1 | 4 |
问题解决与SQL实现
报错原因
该错误是因为在非EXISTS驱动的子查询中,SELECT子句返回了多列/多表达式,而SQL语法规定这种场景下子查询只能返回单个表达式。比如SELECT * FROM t WHERE col IN (SELECT a,b FROM t2)这类写法就会触发报错。
实现思路
- 先拆分原表中逗号分隔的
StudentId字段(以SQL Server为例,使用STRING_SPLIT,其他数据库可替换为对应拆分函数); - 分别对两个表按预期的Student分组统计费用和计数;
- 通过全连接合并两个表的统计结果,规避子查询返回多列的问题。
完整SQL语句
-- 处理表1的拆分与统计 WITH Table1_Stats AS ( SELECT CASE WHEN 已缴学校费用 <= 10000 THEN 'Student1' WHEN 已缴学校费用 <= 40000 THEN 'Student2' WHEN 已缴学校费用 <= 70000 THEN 'Student3' WHEN 已缴学校费用 <= 80000 THEN 'Student4' ELSE 'Student5' END AS StudentGroup, SUM(已缴学校费用) AS 已缴学校费用, COUNT(*) AS Count3 FROM ( SELECT s.value AS StudentId, t.StuName, t.已缴学校费用 FROM 表1 t CROSS APPLY STRING_SPLIT(t.StudentId, ',') s ) t GROUP BY CASE WHEN 已缴学校费用 <= 10000 THEN 'Student1' WHEN 已缴学校费用 <= 40000 THEN 'Student2' WHEN 已缴学校费用 <= 70000 THEN 'Student3' WHEN 已缴学校费用 <= 80000 THEN 'Student4' ELSE 'Student5' END ), -- 处理表2的拆分与统计 Table2_Stats AS ( SELECT CASE WHEN 已缴学费 <= 7000 THEN 'Student1' WHEN 已缴学费 <= 10000 THEN 'Student2' WHEN 已缴学费 <= 6000 THEN 'Student3' WHEN 已缴学费 <= 4000 THEN 'Student4' ELSE 'Student5' END AS StudentGroup, SUM(已缴学费) AS 已缴学费, COUNT(*) AS Count4 FROM ( SELECT s.value AS StudentId, t.StuName, t.已缴学费 FROM 表2 t CROSS APPLY STRING_SPLIT(t.StudentId, ',') s ) t GROUP BY CASE WHEN 已缴学费 <= 7000 THEN 'Student1' WHEN 已缴学费 <= 10000 THEN 'Student2' WHEN 已缴学费 <= 6000 THEN 'Student3' WHEN 已缴学费 <= 4000 THEN 'Student4' ELSE 'Student5' END ) -- 合并统计结果 SELECT COALESCE(t1.StudentGroup, t2.StudentGroup) AS '', COALESCE(t1.已缴学校费用, 0) AS 已缴学校费用, COALESCE(t2.已缴学费, 0) AS 已缴学费, COALESCE(t1.Count3, 0) AS Count3, COALESCE(t2.Count4, 0) AS Count4 FROM Table1_Stats t1 FULL JOIN Table2_Stats t2 ON t1.StudentGroup = t2.StudentGroup ORDER BY COALESCE(t1.StudentGroup, t2.StudentGroup);
说明
- 字符串拆分:如果使用MySQL/PostgreSQL等数据库,需替换
STRING_SPLIT为对应函数(如MySQL用递归拆分,PostgreSQL用STRING_TO_ARRAY); - 分组规则:示例中的分组逻辑是匹配预期输出的费用区间,可根据实际业务需求调整;
- 报错规避:通过CTE分别处理两个表的统计,再用JOIN合并结果,彻底避免了子查询返回多列的违规写法。
内容的提问来源于stack exchange,提问作者user21664125
相关产品推荐
相关产品推荐

