使用pivot将列转换为行

时间:2017-07-25 15:05:47

标签: sql-server stored-procedures

我想将cols转换为行以适合图像中的格式 这是我的问题:

Select dt1.Year,dt1.oneyearret as '1-Year Retention',dt2.twoyearret as '2-Year Retention',dt4.fouryeargrad as '4-Year Graduation Rate',dt5.fiveyeargrad as '5-Year Graduation Rate',dt6.sixyeargrad as '6-Year Graduation Rate' from
(select case WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2015' then '2015' WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2016' then '2016' else (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)))  end  as 'Year',
                                  cast(convert(varchar,(Convert(Money,SUM(rg.RET1_FF),1)/Convert(Money,SUM(rg.COHORT_COUNT),1))*100,1) as numeric(10,1)) as oneyearret         
                                  from vw_Retention_Graduation_F rg
                                  inner join dim_Time t
                                  on rg.TIME_KEY = t.TIME_KEY
                                  inner join dim_Part_Full pf
                                  on rg.PART_FULL_KEY=pf.PART_FULL_KEY
                                  inner join dim_Student_Level sl
                                  on rg.STUDENT_LEVEL_KEY=SL.STUDENT_LEVEL_KEY
                                  inner join dim_Student_Population sp
                                  on rg.STUDENT_POPULATION_KEY=sp.STUDENT_POPULATION_KEY
                                  inner join dim_College c
                                  on rg.COLLEGE_KEY = c.COLLEGE_KEY
                                  WHERE t.ACADEMIC_PERIOD between 201527 and 201627
                                  AND pf.PART_FULL = 'F'
                                  AND sl.STUDENT_LEVEL = 'UG'
                                  AND sp.STUDENT_POPULATION = 'N'
                                  GROUP BY (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)) ) ) dt1 inner join
(select case WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2014' then '2015' WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2015' then '2016' else (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)))  end  as 'Year',
                                  cast(convert(varchar,(Convert(Money,SUM(rg.RET2_FF),1)/Convert(Money,SUM(rg.COHORT_COUNT),1))*100,1) as numeric(10,1)) as twoyearret         
                                  from vw_Retention_Graduation_F rg
                                  inner join dim_Time t
                                  on rg.TIME_KEY = t.TIME_KEY
                                  inner join dim_Part_Full pf
                                  on rg.PART_FULL_KEY=pf.PART_FULL_KEY
                                  inner join dim_Student_Level sl
                                  on rg.STUDENT_LEVEL_KEY=SL.STUDENT_LEVEL_KEY
                                  inner join dim_Student_Population sp
                                  on rg.STUDENT_POPULATION_KEY=sp.STUDENT_POPULATION_KEY
                                  inner join dim_College c
                                  on rg.COLLEGE_KEY = c.COLLEGE_KEY
                                  WHERE t.ACADEMIC_PERIOD between 201427 and 201527
                                  AND pf.PART_FULL = 'F'
                                  AND sl.STUDENT_LEVEL = 'UG'
                                  AND sp.STUDENT_POPULATION = 'N'
                                  GROUP BY (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)) ) ) dt2 on dt1.Year = dt2.year
                                  inner join
(select case WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2012' then '2015' WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2013' then '2016' else (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)))  end  as 'Year',
                                  cast(convert(varchar,(Convert(Money,SUM(rg.GRAD4_FF),1)/Convert(Money,SUM(rg.COHORT_COUNT),1))*100,1) as numeric(10,1)) as fouryeargrad         
                                  from vw_Retention_Graduation_F rg
                                  inner join dim_Time t
                                  on rg.TIME_KEY = t.TIME_KEY
                                  inner join dim_Part_Full pf
                                  on rg.PART_FULL_KEY=pf.PART_FULL_KEY
                                  inner join dim_Student_Level sl
                                  on rg.STUDENT_LEVEL_KEY=SL.STUDENT_LEVEL_KEY
                                  inner join dim_Student_Population sp
                                  on rg.STUDENT_POPULATION_KEY=sp.STUDENT_POPULATION_KEY
                                  inner join dim_College c
                                  on rg.COLLEGE_KEY = c.COLLEGE_KEY
                                  WHERE t.ACADEMIC_PERIOD between 201227 and 201327
                                  AND pf.PART_FULL = 'F'
                                  AND sl.STUDENT_LEVEL = 'UG'
                                  AND sp.STUDENT_POPULATION = 'N'
                                  GROUP BY (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)) ) ) dt4 on dt2.Year = dt4.year
                                  inner join
(select case WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2011' then '2015' WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2012' then '2016' else (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)))  end  as 'Year',
                                  cast(convert(varchar,(Convert(Money,SUM(rg.GRAD5_FF),1)/Convert(Money,SUM(rg.COHORT_COUNT),1))*100,1) as numeric(10,1)) as fiveyeargrad        
                                  from vw_Retention_Graduation_F rg
                                  inner join dim_Time t
                                  on rg.TIME_KEY = t.TIME_KEY
                                  inner join dim_Part_Full pf
                                  on rg.PART_FULL_KEY=pf.PART_FULL_KEY
                                  inner join dim_Student_Level sl
                                  on rg.STUDENT_LEVEL_KEY=SL.STUDENT_LEVEL_KEY
                                  inner join dim_Student_Population sp
                                  on rg.STUDENT_POPULATION_KEY=sp.STUDENT_POPULATION_KEY
                                  inner join dim_College c
                                  on rg.COLLEGE_KEY = c.COLLEGE_KEY
                                  WHERE t.ACADEMIC_PERIOD between 201127 and 201227
                                  AND pf.PART_FULL = 'F'
                                  AND sl.STUDENT_LEVEL = 'UG'
                                  AND sp.STUDENT_POPULATION = 'N'
                                  GROUP BY (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)) ) ) dt5 on dt4.Year = dt5.year
                                  inner join
(select case WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2010' then '2015' WHEN (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4))) ='2011' then '2016' else (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)))  end  as 'Year',
                                  cast(convert(varchar,(Convert(Money,SUM(rg.GRAD6_FF),1)/Convert(Money,SUM(rg.COHORT_COUNT),1))*100,1) as numeric(10,1)) as sixyeargrad         
                                  from vw_Retention_Graduation_F rg
                                  inner join dim_Time t
                                  on rg.TIME_KEY = t.TIME_KEY
                                  inner join dim_Part_Full pf
                                  on rg.PART_FULL_KEY=pf.PART_FULL_KEY
                                  inner join dim_Student_Level sl
                                  on rg.STUDENT_LEVEL_KEY=SL.STUDENT_LEVEL_KEY
                                  inner join dim_Student_Population sp
                                  on rg.STUDENT_POPULATION_KEY=sp.STUDENT_POPULATION_KEY
                                  inner join dim_College c
                                  on rg.COLLEGE_KEY = c.COLLEGE_KEY
                                  WHERE t.ACADEMIC_PERIOD between 201027 and 201127
                                  AND pf.PART_FULL = 'F'
                                  AND sl.STUDENT_LEVEL = 'UG'
                                  AND sp.STUDENT_POPULATION = 'N'
                                  GROUP BY (CONVERT(INT,SUBSTRING(ACADEMIC_PERIOD_all,1,4)) ) )  dt6 on dt5.Year = dt6.year 

电流输出: ![enter image description here

所需输出: ![https://i.stack.imgur.com/FID9g.png

1 个答案:

答案 0 :(得分:1)

用较短的SQL代码替换冗长的SQL代码后,只需生成示例数据,就可以实现这样的实际“转置”操作:

create table tbl (yr int, y1ret float, y2ret float, y4grad float, y5grad float, y6grad float);
insert into tbl VALUES (2015, 83.5, 71.4, 34.8, 54.7, 59.9 ), (2016, 83.6, 73.8, 33.8, 53.6, 60);

select * from (
  select yr, col, value
  from tbl
  unpivot
  (
    value
    for col in (y1ret, y2ret, y4grad, y5grad, y6grad)
  ) unpiv

) src
pivot
(
  max(value)
  for yr in ([2015], [2016])
) piv

这当然是对这里提出的原始解决方案的改编:SQL transpose full table
可在此处找到正在运行的演示:http://rextester.com/CNYR30557

在大多数应用程序中,在接收环境中进行此类操作更简单,更快捷,即在后端使用PHP或在前端使用JavaScript。

修改

为了适应您冗长的SQL代码,您可以这样做:

;WITH tbl AS ( -- YOUR CODE GOES HERE --
)
select * from (
  select yr, col, value
  from tbl
  unpivot
  (
    value
    for col in (y1ret, y2ret, y4grad, y5grad, y6grad)
  ) unpiv

) src
pivot
(
  max(value)
  for yr in ([2015], [2016])
) piv