zoukankan      html  css  js  c++  java
  • sql server 纵横表的转换

      在平常的工作中或者面试中,我们可能有遇到过数据库的纵横表的转换问题。今天我们就来讨论下。

    1.创建表

      首先我们来创建一张表。

    sql语句:

     1 --1. 创建数据表
     2 if OBJECT_ID('Score') is not null drop table Score
     3 
     4 create table Score
     5 (
     6     姓名 nvarchar(128),
     7     课程 nvarchar(128),
     8     分数 int
     9 )
    10 
    11 insert into Score values('张三','语文',98)
    12 insert into Score values('张三','数学',89)
    13 insert into Score values('张三','物理',78)
    14 insert into Score values('李四','语文',79)
    15 insert into Score values('李四','数学',88)
    16 insert into Score values('李四','物理',100)
    17 
    18 select * from Score

    执行结果:

    2. 传统的纵横表转换

    2.1 纵表转横表

    先看看我们要转成的横表张什么样子:

    既然这个表只有两列,那么可以根据姓名进行分组。先把姓名拼凑出来,后面的分数我们再想办法。

    sql:

    select t.姓名 2 from Score as t 3 group by t.姓名 

    结果:

    分析:

    1. 我们先拿到语文这个科目的分数。既然我们用到了group by 语句,这里肯定要用聚合函数来求分数。
    2. 而且我们只需要语文这一科的成绩,分组出来的 一共有 3列 ,分别是 语文、数学、物理  。  那么就需要判断科目来取分数。

      这里符合我们需求的 case 语句就登场了。他和c#中switch-case 作用一样。

    sql case 语句语法: 

    case 字段
        when 值1 then 结果
        when 值2 then 结果2
        ...
        else 默认结果
    end 

    求语文的分数就简单了:

    select t.姓名,
    SUM(case t.课程 when '语文' then t.分数 else 0 end) as 语文
    from Score as t
    group by t.姓名

    结果:

    既然语文的分数取到了,其他科目改变下条件就可以了。

    完整的sql:

    select t.姓名,
    SUM(case t.课程 when '语文' then t.分数 else 0 end) as 语文,
    SUM(case t.课程 when '数学' then t.分数 else 0 end) as 数学,
    SUM(case t.课程 when '物理' then t.分数 else 0 end) as 物理
    from Score as t
    group by t.姓名

    OK,到这儿,我们传统方式的纵表转横表就大功告成了。

    2.2 横表转纵表

    那么我们可以把转换过来的横表再转换回去吗?  

    我们先把刚刚转好的表,插入一个新表ScoreHb 中。

    1 -- 转换的表插入新表
    2 select t.姓名,
    3 SUM(case t.课程 when '语文' then t.分数 else 0 end) as 语文,
    4 SUM(case t.课程 when '数学' then t.分数 else 0 end) as 数学,
    5 SUM(case t.课程 when '物理' then t.分数 else 0 end) as 物理
    6 into ScoreHb
    7 from Score as t
    8 group by t.姓名

    这时ScoreHb 就是我们刚转换好的横表,我们再想办法把他转回来。

    怎么转呢? 一步步来。我们也先把张三和李四的语文成绩查出来。

    sql:

    1 --张三李四语文的分数
    2 select t.姓名,
    3 '语文' as 课程,
    4 t.语文 as 分数
    5 from ScoreHb as t

    结果:

    还有两科的数据怎么办呢? 很简单,我们一个个都查出来,然后用 union all 把他们组合为一张表就可以了。

    sql:

     1 -- union all链接3个科目
     2 select t.姓名,
     3 '语文' as 课程,
     4 t.语文 as 分数
     5 from ScoreHb as t
     6 union all
     7 select t.姓名,
     8 '数学' as 课程,
     9 t.数学 as 分数
    10 from ScoreHb as t
    11 union all
    12 select t.姓名,
    13 '物理' as 课程,
    14 t.物理 as 分数
    15 from ScoreHb as t
    16 order by t.姓名 desc

    结果:

    这样,我们就把表又变回去了。

    但是大家有没有觉得很麻烦呢?别急,我们有更简单的办法。下面为大家介绍pivot关系运算符。

    3. 用pivot和unpivot运算符进行转换

      pivot是sql server 2005 提供的运算符,所以只要数据库在05版本以上的都可以使用。主要用于行和列的转换。

    3.1 pivot纵表转横表

    sql:

    1 select
    2     t2.姓名,
    3     t2.数学,
    4     t2.物理,
    5     t2.语文
    6 from Score as t1
    7 pivot (sum(分数) for 课程 in(数学,语文,物理)) as t2

    结果:

    是不是代码简洁多了。

    pivot将原来表中 课程字段中的 数据行 数学,语文,物理 转换为列,并用sum取对应列的值。

    我们只需要记住它的用法就可以了。

    3.2 unpivot 横表转纵表

    既然有privot可以纵表转横表。那么有没有运算符帮我们转回来呢?

    答案是肯定的,他就是unpivot

    sql:

    1 select
    2     *
    3 from
    4 ScoreHb
    5 unpivot (分数 for 课程 in (语文,数学,物理)) as t4

    结果:

     unpivot 将 语文,数学,物理 列转为行,分数为新的一列存放对应的值。

     是不是比我们之前一个个表查询拼接,方便了很多。

  • 相关阅读:
    Mysql查询语句,select,inner/left/right join on,group by.....[例题及答案]
    Java IO实现文件(及文件夹)的复制 原创代码【精】
    [精华帖]Java接口怎么定义?如何使用?【实例讲解】
    Java面向对象中this关键字详解 意义+实例讲解【hot】
    linux系统编程之进程(三):进程复制fork,孤儿进程,僵尸进程
    linux系统编程之进程(二):进程生命周期与PCB(进程控制块)
    linux系统编程之进程(一):进程与程序
    linux系统编程之文件与IO(八):文件描述符相关操作-dup,dup2,fcntl
    linux系统编程之文件与IO(七):时间函数小结
    linux系统编程之文件与IO(六):实现ls -l功能
  • 原文地址:https://www.cnblogs.com/simple-blog/p/4371240.html
Copyright © 2011-2022 走看看