sql转置 -- 行转列,使用case when、if

本文详细介绍了SQL中转置操作的实现方法,包括使用CASE WHEN或IF语句进行简单转置,以及结合GROUP BY和聚合函数进行复杂数据汇总。同时,深入探讨了GROUP_CONCAT函数的用法,展示如何将同一分组的记录连接成字符串,适用于显示每个学生的所有科目及其成绩等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SQL转置的一般办法

  转置使用 case when 或 if都可以。

select 
	 case 
	 when 条件1  then 翻译值1  
	 when 条件2  then 翻译值2  
	 else  缺省值 
from tableName;
select ... ,
	if(条件1,翻译值1,缺省值),
	if(条件2,翻译值2,缺省值)
from tableNmae;

  但是,如果是分组后再转置;也就是需要先group by再转置,则需要对case when 或 if 使用聚合函数。即: group by和聚合函数要么都出现,要么都不出现。

select ... ,
	max(if(条件1,翻译值1,缺省值)),
	max(if(条件2,翻译值2,缺省值))
from tableNmae group by 条件中的列;	

  MAX函数,可以返回多个字符串中ASCII最大的字符串,不过使用中要注意,它可能改变返回的数据类型(String->BLOB)。另外,MAX也可以用GROUP_CONCAT函数代替,它是将同一group by的记录连接起来。

group_concat用法

	([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] 
	    [Separator '分隔符'])

执行该sql语句:

	select name, group_concat(subject, grade separator '&') 
	from student 
	group by name;
-- 上面的sql语句意思是: 在一列中,显示每个学生的科目及成绩。

这是执行的结果:

+----------+-------------------------------------------+
| name     | group_concat(subject,grade separator '&') |
+----------+-------------------------------------------+
| lisi     | 数学67&语文76                              |
| zhang    | 语文80&数学70                              |
| wangwu   | 语文87&数学97                              |
+----------+-------------------------------------------+

一些简单的SQL转置的例子

这是表的数据
这是表的数据

这是表的结构
这是表的结构

这个表存储的是每个人每笔充值的信息,分别是id,充值人姓名,充值时间,支付方式,充值金额,是否充值成功

1. 查询每天,每种充值方式的充值金额。

这是执行结果:
执行结果
这是比较简单的sql转置。

select createtime,
           case paytype when '支付宝' then money end as '支付宝',
           case paytype when '手机短信' then money end as '手机短信'
	from inpours ;



2. 查询每天,每种充值方式的金额最多的金额。

查询结果如图所示:
查询结果

sql如下:

select createtime,
		max( case paytype when '支付宝' then money end )as '支付宝',
		max(case paytype when '手机短信' then money end )as '手机短信'
	from inpours group by createtime;


3. 查询每天,每种充值方式的金额的总和。

查询结果如图所示:
查询结果

sql如下:

select createtime, sum(money) from inpours group by createtime,paytype;


4. 查询每天,每种充值方式的金额的信息。

查询结果如图所示:
产讯结果

select createtime, paytype,sum(money) from inpours group by createtime,paytype;


5. 查询每天,每种充值方式的金额的总和。

查询结果如图所示:
这里写图片描述

select createtime, paytype,sum(money) from inpours group by createtime,paytype;


6. 查询每天,每种充值方式的金额的总和(去掉null)。

查询结果如图所示:
查询结果

sql如下:

select createtime, paytype,sum(money) from inpours group by createtime,paytype;
<think>嗯,用户想了解如何使用CASE WHEN进行行转列操作。首先,我需要回忆一下SQL中的CASE WHEN语句的基本用法,以及行转列的概念。行转列通常是把多行数据转换成多个列,或者将多个列的值展开为多行。CASE WHEN在这里可能用于条件判断,为每个新列生成对应的值。 记得之前学过的,行转列有时也称为数据透视(Pivot),而列转行则是逆透视(Unpivot)。用户提到的引用里有使用UNPIVOT的例子,但用户现在想用CASE WHEN实现行转列,可能是在不支持PIVOT函数的情况下手动实现。 首先,行转列的基本思路应该是根据某个字段的值,将不同的行数据分配到不同的列中。例如,如果有一个科目字段,包含语文、数学、英语,那么行转列后,每个学生的这三个科目成绩会成为三个不同的列。这时候,使用CASE WHEN对每个科目进行判断,当科目是语文时,显示成绩,否则显示NULL或其他默认值,然后通过聚合函数(如MAX或SUM)来将多行合并为一行。 需要确认的是,在使用CASE WHEN时,是否需要结合GROUP BY和聚合函数。比如,每个学生的每个科目成绩可能对应不同的行,通过GROUP BY学生姓名,然后对每个科目使用MAX(CASE WHEN subject='语文' THEN score END) AS 语文,这样就能把同一学生的不同科目成绩转成列。 接下来,用户可能需要一个具体的示例。例如,原始数据表结构是学生姓名、科目、成绩,转成姓名、语文、数学、英语三个列。这时候,需要用CASE WHEN分别处理每个科目,然后聚合。 另外,用户提供的引用中有提到UNION ALL的方法,但用户问的是CASE WHEN,所以可能需要忽略UNION ALL的方法,专注于CASE WHEN结合GROUP BY的方式。 还要注意,不同的数据库系统可能对PIVOT有不同支持,比如SQL Server有PIVOT关键字,但如果是通用的SQL,可能需要手动用CASE WHEN实现。用户的问题没有指定数据库,所以应该用通用的方法回答。 现在,需要整理步骤:1. 确定需要转置的行值(如科目);2. 为每个需要转换的值创建CASE WHEN语句;3. 使用聚合函数和GROUP BY进行分组汇总。 然后给出示例,比如原始表student_scores有name, subject, score。使用CASE WHEN为每个subject生成列,然后GROUP BY name,这样每个name对应一行,各科成绩作为列。 可能还需要提到处理重复数据或NULL值的情况,比如使用MAX或者SUM来确保每个学生每个科目只有一个成绩,避免重复行。如果存在多个成绩,可能需要根据业务需求决定如何处理。 最后,总结使用CASE WHEN实现行转列的优缺点,比如灵活但代码量大,适合静态列的情况,而动态列可能需要动态SQL。引用中的例子[^4]提到了UNPIVOT,但用户的问题是关于CASE WHEN,所以应该引用相关的部分,比如引用[2]中的CASE WHEN语句的灵活使用,或者引用[1]中的基本用法。</think>### SQL CASE WHEN实现行转列操作详解 #### 一、核心原理 行转列(Pivot)的核心是通过条件判断将行数据转换为多列。使用`CASE WHEN`对原始数据中的**行值**进行分类,再配合聚合函数和`GROUP BY`实现数据重组。例如,将科目(数学、语文、英语)的行数据转换为横向排列的列。 #### 二、操作步骤 1. **确定分类字段**:选择需要转换为列的字段(如`subject`字段中的"数学"、"语文"等)。 2. **编写条件表达式**:为每个目标列创建`CASE WHEN`语句。 3. **聚合数据**:使用`MAX()`或`SUM()`等聚合函数合并重复行。 4. **分组汇总**:通过`GROUP BY`对保留的维度字段(如学生姓名)分组。 #### 三、具体示例 **原始表结构**:`student_scores` | name | subject | score | |-------|---------|-------| | 张三 | 语文 | 85 | | 张三 | 数学 | 90 | | 李四 | 英语 | 78 | **目标结构**: | name | 语文 | 数学 | 英语 | |-------|------|------|------| | 张三 | 85 | 90 | NULL | | 李四 | NULL | NULL | 78 | **SQL实现**: ```sql SELECT name, MAX(CASE WHEN subject = '语文' THEN score END) AS 语文, MAX(CASE WHEN subject = '数学' THEN score END) AS 数学, MAX(CASE WHEN subject = '英语' THEN score END) AS 英语 FROM student_scores GROUP BY name; ``` - **关键点**:`MAX()`用于确保每个学生每个科目仅保留一个值(若存在多个记录需根据场景选择聚合方式)[^2]。 #### 四、适用场景与限制 - **静态列**:需提前明确目标列(如已知科目类型)[^3]。 - **动态列**:若列不固定,需结合动态SQL生成(复杂,需数据库支持)。 - **性能**:适用于中小规模数据,大规模数据建议使用数据库内置的`PIVOT`函数(如SQL Server)[^4]。 #### 五、扩展应用 ```sql -- 添加总分计算 SELECT name, MAX(CASE WHEN subject = '语文' THEN score END) AS 语文, MAX(CASE WHEN subject = '数学' THEN score END) AS 数学, SUM(score) AS 总分 FROM student_scores GROUP BY name; ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值