• sql行列旋转


    一,行转列

    先建立测试数据 

    复制代码
    if OBJECT_ID('week_income') is not null
    drop table week_income
    go
    create table week_income
    (
        employee varchar(10),
        weekname varchar(10),
        income int
    )
    go
    insert into week_income
    select '張三','星期一',1000 union all
    select '張三','星期二',2000 union all
    select '張三','星期三',1500 union all
    select '張三','星期四',2000 union all
    select '張三','星期五',3000 union all
    select '張三','星期六',4000 union all
    select '張三','星期日',5000 union all
    select '李四','星期一',1000 union all
    select '李四','星期二',2000 union all
    select '李四','星期三',1500 union all
    select '李四','星期四',2000 union all
    select '李四','星期五',3000 union all
    select '李四','星期六',4000 union all
    select '李四','星期日',8000 
    
    select * from week_income
    复制代码

     

    1.1 用传统的case when 语法实现行转列。

    复制代码
    select employee as '社員'
          ,sum(case weekname when '星期一' then income else 0 end) as '星期一'
          ,sum(case weekname when '星期二' then income else 0 end) as '星期二'
          ,sum(case weekname when '星期三' then income else 0 end) as '星期三'
          ,sum(case weekname when '星期四' then income else 0 end) as '星期四'
          ,sum(case weekname when '星期五' then income else 0 end) as '星期五'
          ,sum(case weekname when '星期六' then income else 0 end) as '星期六'
          ,sum(case weekname when '星期日' then income else 0 end) as '星期日'                              
    from week_income
    group by employee
    复制代码

    1.2 用sqlserver2005以后新增加的pivot语法实现行转列。 

    pivot的语法如下: 

    复制代码
    SELECT <non-pivoted column>, 
        [first pivoted column] AS <column name>, 
        [second pivoted column] AS <column name>, 
        ... 
        [last pivoted column] AS <column name> 
    FROM 
        (<SELECT query that produces the data>) 
       AS <alias for the source query> 
    PIVOT 
    ( 
        <aggregation function>(<column being aggregated>) 
    FOR 
    [<column that contains the values that will become column headers>] 
        IN ( [first pivoted column], [second pivoted column], 
        ... [last pivoted column]) 
    ) AS <alias for the pivot table> 
    <optional ORDER BY clause>;
    复制代码
    复制代码
    select employee  as '社員',[星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日] --step 3
    from (select employee ,weekname,income from week_income) t -- step 2
    pivot
    (
        --step 1
        sum(income) for weekname in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
    ) b
    复制代码

    pivot分为3个步骤:

    1,进行行列转换

    sum(income) for weekname in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
    注意:聚合函数sum等是决定重复行数据的处理方法,比如有两个星期一,就把这两个值合并了。 

    2,定义检索数据源(select employee ,weekname,income from week_income) t

    注意别名t不能省略。这里要特别注意employee这一列并没有在步骤1中出现,sqlserver会默认按employee进行分组,这个功能挺棒的。

    3,选择结果集中的列,全部选择可以用*。

    employee  as '社員',[星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]
    注意:可以对列名取别名,也可以只检索其中的部分列,而不必全部检索出所有列。

    转换结果

    二,列转行

    以上面的转换结果作为数据表,我们先把结果导入到一张tmp的表中

    复制代码
    select * into tmp from (
    select employee  as '社員',[星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]
    from (select employee ,weekname,income from week_income) t
    pivot
    (
        sum(income) for weekname in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
    ) b
    ) c
    
    select * from tmp 
    复制代码

    然后,我们将星期一到星期日这几列转换到行上。

    2.1 用传统的union all方法。

    复制代码
    select 社員 as employee,'星期一' as weekname, 星期一 as income from tmp union all
    select 社員 as employee,'星期二' as weekname, 星期二 as income from tmp union all
    select 社員 as employee,'星期三' as weekname, 星期三 as income from tmp union all
    select 社員 as employee,'星期四' as weekname, 星期四 as income from tmp union all
    select 社員 as employee,'星期五' as weekname, 星期五 as income from tmp union all
    select 社員 as employee,'星期六' as weekname, 星期六 as income from tmp union all
    select 社員 as employee,'星期日' as weekname, 星期日 as income from tmp
    order by 社員
    复制代码

    2.2 用sqlserver2005以后新增的unpivot方法。

    复制代码
    select 社員 as employee, weekname,income
    from (select 社員,[星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日] from tmp) a
    unpivot
    (
        income for weekname in ([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日] )
    ) b
    复制代码

    unpivot是pivot的逆操作,income和weekname都是需要创建的新列,income指代数据的值,weekname指代列名的值。

    转换后的结果和我们最初建立的表一模一样

     三,动态实现行列旋转

    上面的方式,都是代码写了几个固定值旋转,没有实现动态列,扩展性不强。

    要实现动态,主要使用拼sql的方式实现,以行转列的传统写法做个例子,其他的可以举一反三。

    复制代码
    declare @sql as varchar(4000)
    set @sql = 'select employee as ''社員'''
    
    select @sql = @sql + ',sum(case weekname when ''' + weekname + ''' then income else 0 end) as ''' + weekname + ''''
    from (
        select distinct weekname from week_income) a
    set  @sql =@sql + ' from week_income    '
    set  @sql =@sql + ' group by employee    '
    print @sql
    exec (@sql)
    复制代码

    结果也是这样

  • 相关阅读:
    996工作制是奋斗还是剥削?
    动态链接的PLT与GOT
    The Product-Minded Software Engineer
    缓冲区溢出
    golang的加法比C快?
    C errno是否是线程安全的
    golang 三个点的用法
    GDB 单步调试汇编
    为什么CPU需要时钟这种概念?
    fliebeat配置手册
  • 原文地址:https://www.cnblogs.com/bluedy1229/p/6217112.html
Copyright © 2020-2023  润新知