LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

SQL行列转换实战:让报表数据“横竖自如”

admin
2026年1月21日 21:3 本文热度 873
你是否遇到过这样的场景:数据库中数据是一行一个记录存放的,但是需求要:一行代表一个完整对象。这种行列转换的需求在数据分析中无处不在,今天一起来看看这个问题。

一、行列转换重要性

想象一下这些工作场景:
人事部门:数据库每个员工有多条培训记录,但是领导想要一张表,每个员工一行,培训成绩的汇总表。
销售部门:原始数据是按照天记录的销售额,月报需要按照产品横向展示出每月总的销售额。
财务部门:科目余额是纵向存储的,但是资产负债表需要横向对比数据。
这些都是行列转转换的实际工作需求,也是通过行列转换技巧能处理的问题:让数据按照需要的格式,而不是被数据库存储格式限制

二、行转列:把"竖着看"变成"横着看"

场景再现:学生的考试成绩表转换
原始数据:每个学生每个科目占一行记录
    姓名   | 科目   | 分数------|--------|------张三  | 数学   | 90张三  | 英语   | 85李四  | 数学   | 95李四  | 英语   | 80
    目标格式:每个学生占一行,各个科目作为列呈现
      姓名   | 数学 | 英语------|------|------张三  | 90   | 85李四  | 95   | 80
      方法1:万能公式-case when +聚合函数
        SELECT     name AS 姓名,    MAX(CASE WHEN subject = '数学' THEN score ENDAS 数学,    MAX(CASE WHEN subject = '英语' THEN score ENDAS 英语,    MAX(CASE WHEN subject = '语文' THEN score ENDAS 语文FROM student_scoresGROUP BY name;
        关键点
        case when: 将行数据旋转为列
        聚合函数(max/sum):确保每个分组只返回一行
        为什么用max: 因为每个学生学科只有一个分数,max是取唯一值
        方法2:优雅写法-PIVOT(sqlserver)
          -- SQL Server的PIVOT语法SELECT *FROM student_scoresPIVOT (    MAX(score)  -- 要聚合的数值    FOR subject  -- 要转换为列名的字段    IN ('数学' AS math_score, '英语' AS english_score)  -- 具体转换规则);
          关键点:把subject字段的不同值(数学、英语)变成新的列名,把对应的score值填进去。

          三、列转行:把"横着看"变回"竖着看"

          场景再现:销售报表转换
          原始数据:每行是产品各个季度销售额:
            产品     | Q1销售额 | Q2销售额 | Q3销售额--------|----------|----------|----------手机    | 1000     | 1200     | 1500电脑    | 2000     | 1800     | 2200
            目标格式:每行是一个产品一个季度的销售额
              产品     | 季度 | 销售额--------|------|--------手机    | Q1   | 1000手机    | Q2   | 1200手机    | Q3   | 1500电脑    | Q1   | 2000电脑    | Q2   | 1800电脑    | Q3   | 2200
              方法1:简单直接-UNION ALL
                SELECT product AS 产品, 'Q1' AS 季度, Q1销售额 AS 销售额 FROM salesUNION ALLSELECT product AS 产品, 'Q2' AS 季度, Q2销售额 AS 销售额 FROM salesUNION ALLSELECT product AS 产品, 'Q3' AS 季度, Q3销售额 AS 销售额 FROM salesORDER BY 产品, 季度;
                优点:简单直接,所有数据库都支持
                缺点:列的数量过多时,代码会很冗长,容易出错
                方法2:专业工具-UNPIVOT
                  -- SQL Server/Oracle的UNPIVOT语法SELECT 产品, 季度, 销售额FROM salesUNPIVOT (    销售额    FOR 季度 IN (Q1销售额, Q2销售额, Q3销售额)AS unpvt;
                  关键点:把多个列(Q1销售额、Q2销售额...)变成多行,每行包含原列名和值。

                  四、实战经验:避免常见的坑

                  坑1:null值处理陷阱
                    -- 问题:如果某学生缺考,分数是NULLSELECT     name,    MAX(CASE WHEN subject = '数学' THEN score ENDAS 数学    -- 这里会返回NULL,但可能不是我们想要的FROM student_scoresGROUP BY name;
                    -- 解决方案:使用COALESCE设置默认值SELECT     name,    COALESCE(MAX(CASE WHEN subject = '数学' THEN score END), 0AS 数学    -- 没有成绩时显示0而不是NULLFROM student_scoresGROUP BY name;
                    坑2:性能慢
                    场景:100万行数据做行列转换,查询慢怎么办?
                      -- ❌ 低效:全表转换SELECT     user_id,    MAX(CASE WHEN action = 'login' THEN 1 ELSE 0 ENDAS has_login,    MAX(CASE WHEN action = 'purchase' THEN 1 ELSE 0 ENDAS has_purchaseFROM user_actionsGROUP BY user_id;
                      -- ✅ 高效:先过滤再转换SELECT     user_id,    MAX(CASE WHEN action = 'login' THEN 1 ELSE 0 ENDAS has_login,    MAX(CASE WHEN action = 'purchase' THEN 1 ELSE 0 ENDAS has_purchaseFROM user_actionsWHERE action IN ('login''purchase')  -- 先过滤掉无关数据GROUP BY user_id;
                      -- 更高效:添加合适索引CREATE INDEX idx_user_action ON user_actions(user_id, action);

                      五、进阶技巧:多级行列转换

                      场景:月度销售报表(行和列同时转换)
                      原始数据
                        产品   | 月份 | 销售额------|------|--------手机  | 1月  | 1000手机  | 2月  | 1200电脑  | 1月  | 2000电脑  | 2月  | 1800
                        目标格式
                          产品   | 1月销售额 | 2月销售额 | 同比增长------|----------|----------|----------手机  | 1000     | 1200     | 20%电脑  | 2000     | 1800     | -10%
                            SELECT     product AS 产品,    SUM(CASE WHEN month = '1月' THEN amount ENDAS "1月销售额",    SUM(CASE WHEN month = '2月' THEN amount ENDAS "2月销售额",    -- 计算环比增长率    ROUND(        100.0 *         (SUM(CASE WHEN month = '2月' THEN amount END-          SUM(CASE WHEN month = '1月' THEN amount END)) /        NULLIF(SUM(CASE WHEN month = '1月' THEN amount END), 0),        2    ) || '%' AS 环比增长FROM salesGROUP BY product;

                            六、工具选择

                            场景
                            推荐方法
                            优点
                            缺点
                            简单固定行列

                            case when+聚合

                            所有数据库都支持
                            代码长
                            sqlserver/oracle
                            PIVOT/UNPIVOT
                            语法简单,可读性高
                            数据库限制
                            大数据平台

                            EXPLODE(LATERAL VIEW)

                            适合处理数组/map
                            语法独特

                            七、总结

                            1. 行转换成列= 分组 +条件取值
                            用group by确定每一行
                            用case when 把其他行的值拿到当前行
                            2. 列转换成行= 列拆解+ 行合并
                            把一行的多列拆成多行
                            用union all把拆解结果合并
                            3. 性能关键= 索引+过滤
                            建立索引,否则百万数据转换慢
                            先过滤无关数据,再进行转换
                            行列转换就像数据世界的"乾坤大挪移",掌握了它,你就掌握了让数据"听话"的能力。


                            阅读原文:原文链接


                            该文章在 2026/1/22 13:35:19 编辑过
                            关键字查询
                            相关文章
                            正在查询...
                            点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
                            点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
                            点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
                            点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
                            Copyright 2010-2026 ClickSun All Rights Reserved