Oracle行转列核心逻辑+实操笔记
一、行转列 “万能口诀”(核心逻辑)
这两句口诀是行转列的底层逻辑,适用于所有场景:
分组列定行数,分类列定列数,值字段填内容;
CASE WHEN 判 “分类列的取值”,THEN 填 “值字段的内容”。
二、口诀与代码对应关系(原奖品表例子验证)
| 核心口诀 | 对应 Oracle 代码片段 | 落地解释 |
|---|---|---|
| 分组列定行数 | GROUP BY user_name | 分组列是user_name,结果行数 = 分组数(张三、李四→2 行) |
| 分类列定列数 | CASE WHEN t.award_name = ‘ 手机 ‘/‘ 大米’ | 分类列是award_name,取值数量决定基础列数 |
| 值字段填内容 | THEN t.award_name / THEN t.create_date | 值字段是award_name(奖品名)和create_date(日期),填充到新列 |
| CASE WHEN 判 “分类列的取值” | WHEN t.award_name = ‘ 手机’ | 仅判断分类列的具体值,而非直接使用分类列 |
| THEN 填 “值字段的内容” | THEN t.create_date | 满足判断条件后,填充对应值字段的内容 |
三、关键避坑提醒
列数计算公式:最终列数 = 分类列的取值数量 × 值字段数量
示例验证:分类列取值(手机、大米→2 个)× 值字段(奖品名、日期→2 个)= 4 列(shouji、shouji_create_date、dami、dami_create_date);
若仅保留 1 个值字段(如仅日期),则列数 = 2×1=2 列(手机日期、大米日期)。
聚合函数使用:需用
MAX()/MIN()/SUM()等聚合函数包裹 CASE WHEN,避免分组后出现多行重复数据(因同一分组下可能有多个匹配记录,聚合函数取唯一有效值)。默认值处理:建议用
NULL替代'0'作为 ELSE 结果(日期字段填'0'会导致类型异常,字符串字段填NULL更符合 “无数据” 语义)。
四、原奖品表完整可执行 SQL(优化后)
SELECTt.user_name,-- 手机相关列MAX(CASE WHEN t.award_name = '手机' THEN t.award_name ELSE NULL END) AS shouji,MAX(CASE WHEN t.award_name = '手机' THEN t.create_date ELSE NULL END) AS shouji_create_date,-- 大米相关列MAX(CASE WHEN t.award_name = '大米' THEN t.award_name ELSE NULL END) AS dami,MAX(CASE WHEN t.award_name = '大米' THEN t.create_date ELSE NULL END) AS dami_create_dateFROM award tWHERE t.award_name IN ('手机', '大米') -- 过滤分类列取值,优化性能GROUP BY t.user_name;
五、新场景实操:成绩分数行转列(验证通用性)
场景说明
现有成绩表score,字段:student_name(学生姓名)、subject(科目)、score(分数)、exam_date(考试日期);
需求:行转列展示每个学生的「语文分数、语文考试日期、数学分数、数学考试日期」,每个学生仅 1 行数据。
套用口诀写 SQL
分组列:
student_name(定行数→学生数量 = 结果行数);分类列:
subject(定列数→取值:语文、数学→2 个);值字段:
score(分数)、exam_date(考试日期)→2 个;最终列数:2×2=4 列(语文分数、语文日期、数学分数、数学日期)。
完整 SQL 代码
SELECTstudent_name,-- 语文相关列(分类列取值=语文,值字段=分数/日期)MAX(CASE WHEN subject = '语文' THEN score ELSE NULL END) AS chinese_score,MAX(CASE WHEN subject = '语文' THEN exam_date ELSE NULL END) AS chinese_exam_date,-- 数学相关列(分类列取值=数学,值字段=分数/日期)MAX(CASE WHEN subject = '数学' THEN score ELSE NULL END) AS math_score,MAX(CASE WHEN subject = '数学' THEN exam_date ELSE NULL END) AS math_exam_dateFROM scoreWHERE subject IN ('语文', '数学') -- 过滤无关科目GROUP BY student_nameORDER BY student_name; -- 按学生姓名排序,优化阅读
示例数据与执行结果
| student_name | chinese_score | chinese_exam_date | math_score | math_exam_date |
|---|---|---|---|---|
| 小明 | 92 | 2024-06-10 | 88 | 2024-06-11 |
| 小红 | 95 | 2024-06-10 | 93 | 2024-06-11 |
六、总结
行转列本质:通过「分组列聚合 + 分类列判断 + 值字段填充」,将多行数据压缩为一行;
口诀是核心:无论场景如何变化,只要确定「分组列、分类列取值、值字段」,就能直接套用;
避坑关键:记住列数计算公式,用聚合函数包裹 CASE WHEN,默认值用
NULL。
(注:文档部分内容可能由 AI 生成)
