SQL语句 case... when...then...练习题及答案

本文通过两个具体案例,展示了如何使用SQL进行数据处理和分析。第一个案例中,我们对球队比赛结果进行了汇总,计算了各队的胜败场次;第二个案例则处理了票据金额,将正数视为收入,负数视为支出,清晰地展示了财务状况。

练习题1

原表格:
加粗样式
要求处理后呈现如下:
在这里插入图片描述

结果如下

//创建表格
create table team (name char(8),result nchar(1),id serial);

insert into TEAM (name, result) values
(N'火箭',1),
(N'奇才',1),
(N'湖人',1),
(N'火箭',0),
(N'火箭',0),
(N'奇才',1)
;

=> select * from team;
  NAME  | RESULT | COUNTRY | ID
--------+--------+---------+----
 奇才   | 胜     | CN      |  4
 奇才   | 胜     | CN      |  6
 湖人   | 胜     | CN      |  5
 火箭   | 胜     | CN      |  3
 火箭   | 败     | CN      |  1
 火箭   | 败     | CN      |  2
(6 rows)

=> select name,
sum(case when result = N'胜' then 1 else 0 end) as ’胜‘,
sum(case when result = N'败' then 1 else 0 end) as ’败‘
from team group by name;
-> -> ->   
NAME  | ’胜‘ | ’败‘
--------+------+------
 火箭   |    1 |    2
 奇才   |    2 |    0
 湖人   |    1 |    0
(3 rows)


练习题2:

原表格:
在这里插入图片描述
处理后呈现成以下格式:
在这里插入图片描述

结果:

操作方法如下:

//创建表
create table test1 (Ticket varchar(4),Amount int);

//写入参数
=> insert into test1 (Ticket, Amount) values
('tk1',10),
('tk2',20),
('tk3',-30),
('tk4',0),
('tk5',-10);
-> INSERT 0 5


//查表
=> select * from test1;
 TICKET | AMOUNT
--------+--------
 tk1    |     10
 tk2    |     20
 tk3    |    -30
 tk4    |      0
 tk5    |    -10
(5 rows)

//结果输出
=> select ticket,
(
case
when AMOUNT >= 0 then AMOUNT
else 0
end
) as income,
(
case
when AMOUNT >=0 then 0
else AMOUNT
end
) as expense
from test1;
->  TICKET | INCOME | EXPENSE
--------+--------+---------
 tk1    |     10 |       0
 tk2    |     20 |       0
 tk3    |      0 |     -30
 tk4    |      0 |       0
 tk5    |      0 |     -10
(5 rows)```


<think> 我们首先分析用户的问题:用户希望理解和优化SQL语句中的CASE WHEN条件判断部分,具体例子是`CASE WHEN sc.grade>=60 THEN cou.credit ELSE 0 END as credit`。用户可能是在计算学生获得的学分,当成绩大于等于60分时,获得该课程的学分,否则获得0。 根据引用内容,我们可以看到在引用[2]和引用[5]中使用了类似的CASE WHEN语句进行条件统计。特别是引用[2]中,使用了多个CASE WHEN来统计不同分数段的人数。引用[4]展示了在UPDATE语句中使用CASE WHEN进行条件更新。 用户提供的例子是一个典型的条件赋值,它用于在查询结果中根据条件产生不同的值。这种用法在SQL中非常常见,并且通常没有性能问题,因为它只是对每一行数据进行判断。 但是,如果用户担心性能或者有更复杂的逻辑,我们可以考虑优化。不过,在这个简单的例子中,优化空间不大。如果这个查询是在一个大数据集上运行,并且我们只关心学分总和(而不是每一行的明细),那么我们可以考虑在聚合函数中使用这个条件表达式,从而避免在每一行都计算(但实际上,聚合函数中也需要对每一行计算,所以可能差别不大)。 另外,用户提供的例子中,`sc.grade`和`cou.credit`分别来自两个表(假设sc是成绩表,cou是课程表),所以可能需要连接操作。如果连接操作导致数据量变大,那么优化连接可能比优化CASE WHEN更重要。 下面我们分步骤解释和优化: 1. 理解原语句的作用: - 当成绩(sc.grade)大于等于60时,返回该课程的学分(cou.credit),否则返回0。 - 这个表达式通常用于计算每个学生每个课程实际获得的学分(通过考试则得学分,否则不得)。 2. 优化建议: a) 确保连接条件正确,并使用索引:由于这个查询可能涉及连接,确保连接字段有索引,以减少连接时间。 b) 如果不需要明细,只需要总学分,那么使用聚合函数(如SUM)来汇总,避免返回大量明细数据。 c) 考虑使用IF函数(如果数据库支持,例如MySQL):在MySQL中,可以使用IF(condition, true_value, false_value)来简化,但CASE WHEN是标准SQL,兼容性更好。 3. 改写示例: 原表达式: CASE WHEN sc.grade>=60 THEN cou.credit ELSE 0 END as credit 如果只需要每个学生的总学分,可以这样写: SELECT sc.student_id, SUM(CASE WHEN sc.grade>=60 THEN cou.credit ELSE 0 END) as total_credit FROM sc JOIN cou ON sc.course_id = cou.course_id GROUP BY sc.student_id 4. 性能考虑: - 在连接表时,确保连接字段有索引(例如sc.course_id, cou.course_id, 以及sc.student_id)。 - 如果成绩表(sc)和课程表(cou)数据量很大,可以考虑在WHERE子句中先过滤掉不需要的行(例如只查询某个学期的数据)。 5. 其他注意事项: - 注意处理NULL值:如果成绩可能是NULL,那么需要决定如何处理。原表达式在成绩为NULL时会进入ELSE分支(即0)。如果希望将NULL视为不及格,这样处理是合适的;如果希望将NULL视为特殊值,可能需要单独处理。 6. 复杂条件优化: - 如果条件非常复杂(例如多个条件嵌套),可以考虑使用视图或者临时表来分步计算,以提高可读性。 综上所述,这个CASE WHEN表达式本身是高效的,优化重点应放在连接操作和索引上。 下面我们生成相关问题: </think> ### SQL中`CASE WHEN`条件判断的用法与优化 #### 1. **基本用法解析** 在SQL语句中: ```sql CASE WHEN sc.grade >= 60 THEN cou.credit ELSE 0 END AS credit ``` - **作用**:根据成绩`grade`的值动态计算学分`credit` - **执行逻辑**: - 若成绩 ≥ 60,返回课程学分`cou.credit` - 若成绩 < 60,返回`0` - **应用场景**:常见于成绩学分转换、条件统计(如引用[2][^2]和引用[5][^5]的分段统计) #### 2. **性能优化方案** 当数据量较大时,可通过以下方法优化: ##### (1) **减少数据扫描范围** 添加筛选条件,避免全表扫描: ```sql SELECT CASE WHEN sc.grade >= 60 THEN cou.credit ELSE 0 END AS credit FROM score sc JOIN course cou ON sc.course_id = cou.id WHERE sc.grade IS NOT NULL -- 排除无效数据 AND sc.semester = '2023-Fall' -- 限定范围 ``` ##### (2) **避免重复计算** 若需聚合统计,直接在`SUM()`中嵌入`CASE WHEN`: ```sql SELECT SUM(CASE WHEN sc.grade >= 60 THEN cou.credit ELSE 0 END) AS total_credit FROM score sc JOIN course cou ON sc.course_id = cou.id ``` > ✅ **优点**:单次遍历完成计算(引用[5][^5]的优化方案) ##### (3) **索引优化** 对常用筛选字段创建索引: ```sql CREATE INDEX idx_grade ON score(grade); -- 成绩字段索引 CREATE INDEX idx_course ON course(id, credit);-- 课程表复合索引 ``` ##### (4) **简化条件逻辑** 若只有单条件判断,可改用`IF()`函数(MySQL/Oracle适用): ```sql SELECT IF(sc.grade >= 60, cou.credit, 0) AS credit -- 更简洁的写法 ``` #### 3. **常见问题处理** - **NULL值处理**: ```sql CASE WHEN sc.grade >= 60 THEN cou.credit WHEN sc.grade IS NULL THEN NULL -- 明确处理NULL ELSE 0 END ``` - **多条件扩展**(如引用[4][^4]的更新操作): ```sql CASE WHEN grade >= 90 THEN credit * 1.2 -- 优秀奖励学分 WHEN grade >= 60 THEN credit ELSE 0 END ``` #### 4. **与连接查询的对比** 用户提到的`LEFT JOIN`方案存在缺陷: ```sql -- 不推荐写法(可能遗漏无成绩记录) SELECT a.date, a.win, b.lose FROM ... LEFT JOIN ... ``` ✅ **推荐**:使用`CASE WHEN`单次分组聚合(如引用[2][^2]),避免连接风险和NULL值问题。 --- ### 相关问题 1. 如何在`SUM()`函数中嵌入`CASE WHEN`实现条件聚合? 2. 多层级条件判断(如优/良/及格)时,`CASE WHEN`如何优化可读性? 3. 对于超大数据集,除了索引还有哪些提升`CASE WHEN`性能的策略? 4. `CASE WHEN`与`IFNULL()`/`COALESCE()`在处理NULL时有何区别? [^2]: SQL常考笔试题[转] [^4]: mysql case when [^5]: SQL 练习
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值