澳门金沙vip 23

澳门金沙vipSQL SERVER 中的行列转换小结

使用PIVOT行转列

1. 介绍表达

前段时间组内的同伴在进级维护项目中,常常提到一些千头万绪的数据转变难点,让本人去看下有个别地方怎么管理,笔者意识众多都以事关到行列转变的主题材料,管理起来平时会相比辛劳,借此也总括一下,方便今后的查阅使用。该计算参照了互连网的一些资料,也做了一部分改成,如有越来越好的点子也款待提出。

示范的台本见 3.测量检验数据脚本

 

1.建表及插入数据

2. 例子演示

2.1 实现行转列

(1) Case WHEN 落成行转列 

澳门金沙vip 1澳门金沙vip 2

/*-----1.1 Case WHEN 实现行转列----------*/

--(1)静态SQL
SELECT [姓名],
 max(CASE 课程 WHEN '语文' THEN 分数 ELSE 0 end) AS 语文,
 max(CASE 课程 WHEN '数学' THEN 分数 ELSE 0 end)AS 数学,
 max(CASE 课程 WHEN '物理' THEN 分数 ELSE 0 end)AS 物理,
 SUM(分数) AS 总分,
 AVG(分数) AS 平均分
FROM tbScore GROUP BY [姓名]

--(2)动态SQL
DECLARE @sql VARCHAR(500)
SET @sql = 'SELECT [姓名]'
SELECT  @sql = @sql + ',MAX(CASE [课程] WHEN ''' + [课程] + ''' THEN [分数] ELSE 0 END)[' + [课程] + ']'
FROM    ( 
            SELECT DISTINCT [课程] FROM tbScore
        ) T1
--同FROM tbScore  GROUP BY [课程],默认按课程名排序
SET @sql = @sql + ' FROM tbScore GROUP BY [姓名]'
PRINT '@sql: ' + @sql
EXEC(@sql)

View Code

 澳门金沙vip 3

 

 (2) PIVOT
实现行反革命转列,此中的NULL值开采还倒霉管理为0

澳门金沙vip 4澳门金沙vip 5

--(1)静态SQL
SELECT  [姓名] ,
        [语文] ,
        [数学] ,
        [物理]
FROM    ( SELECT    [分数] ,
                    [课程] ,
                    [姓名]
          FROM      tbScore
        ) AS SourceTable PIVOT ( AVG([分数]) FOR [课程] IN ( 语文, 数学, 物理 ) ) T


--(2)动态SQL
DECLARE @sql2 VARCHAR(8000)
SET @sql2 = ''
SELECT @sql2 = @sql2 + ',' + [课程] FROM dbo.tbScore GROUP BY [课程]
--STUFF: 删除指定长度的字符,并在指定的起点处插入另一组字符。
SET @sql2= STUFF(@sql2,1,1,'')  --去掉首个','
SET @sql2 = 'SELECT [姓名],' + @sql2 + ' FROM (SELECT [分数],[课程],[姓名] FROM tbScore ) AS SourceTable PIVOT ( AVG([分数]) FOR [课程] IN ( ' + @sql2 + ') ) T'
PRINT @sql2
EXEC(@sql2)

View Code

澳门金沙vip 6

 

2.1 实现转行

 (1) UNION 达成列转行

澳门金沙vip 7澳门金沙vip 8

--(1)静态SQL
SELECT * FROM (
    SELECT [姓名],'语文' AS 课程,[语文] AS 分数 ,[日期] FROM tbScoreNew
    UNION ALL
    SELECT [姓名],'数学' AS 课程,[数学] AS 分数 ,[日期] FROM tbScoreNew
    UNION ALL
    SELECT [姓名],'物理' AS 课程,[物理] AS 分数 ,[日期] FROM tbScoreNew
) T ORDER BY [姓名]

--(2)动态SQL
DECLARE @sql3 VARCHAR(8000)
SELECT @sql3 = ISNULL(@sql3 + ' UNION ALL ','') + ' SELECT [姓名],' + QUOTENAME(name,'''') + ' AS 课程,' + QUOTENAME(name) + ',[日期] FROM tbScoreNew'
FROM sys.columns 
WHERE object_id = OBJECT_ID('tbScoreNew') AND  name NOT IN ('姓名','日期')
SET @sql3 = 'SELECT * FROM ( ' + @sql3  + ' ) T ORDER BY [姓名]'
PRINT @sql3
EXEC (@sql3)

View Code

澳门金沙vip 9

 

 (2) UNPIVOT 完结列转行

澳门金沙vip 10澳门金沙vip 11

--(1)静态SQL
SELECT * FROM (
    SELECT [姓名],[日期],[语文],[数学],[物理] FROM dbo.tbScoreNew
) T UNPIVOT ([分数] FOR [课程] IN ([语文],[数学],[物理])) T2
ORDER BY [姓名]


--(2)动态SQL
DECLARE @sql4 VARCHAR(8000)
SELECT @sql4 = ISNULL(@sql4 + ',','') + QUOTENAME(name)
FROM sys.columns 
WHERE object_id = OBJECT_ID('tbScoreNew') AND  name NOT IN ('姓名','日期')
SET @sql4 = 'SELECT * FROM ( SELECT [姓名],[日期],' + @sql4 + ' FROM dbo.tbScoreNew ) T UNPIVOT ([分数] FOR [课程] IN ('+ @sql4 +')) T2 ORDER BY [姓名]'
PRINT @sql4
EXEC (@sql4)

View Code

澳门金沙vip 12

 

2.3 动态扩张列完毕行转列 

本条参照部门小同伴的项目上的供给写的三个例证,
由于涉及的转变列同临时间有三个字段,用地点的队列调换处理起来都特别不便民,所以接Nabi较常见的动态扩充列的法子管理

测验数据脚本为附属类小部件脚本中的 “3.动态扩展列完成行转列” 脚本

要求:
将【部门预算】、【实际预算】、【剩余预算】遵照年度横向总计展现,且总结数据按机关、项目分组呈现

澳门金沙vip 13澳门金沙vip 14

CREATE TABLE #tmpYear
(
    [YEAR] INT,
    ID INT IDENTITY
)

--保存最终结果
CREATE TABLE #tmpResult
(
    ID INT IDENTITY,
    DeptCode VARCHAR(20),--部门编码
    DeptName NVARCHAR(100), --部门名称
    ProCode VARCHAR(20),--项目编码
    ProName NVARCHAR(100),--项目名称
    KeyCode VARCHAR(50)
)
GO

--1.写入分组数据
INSERT INTO #tmpResult( DeptCode ,DeptName , ProCode ,ProName,KeyCode)
SELECT DeptCode,MAX(DeptName), ProCode,MAX(ProName),DeptCode + '_' + ProCode FROM tbDeptBudget GROUP BY DeptCode,ProCode

--2.计算预算结果数据
--写入年份数据
INSERT INTO #tmpYear SELECT DISTINCT Year FROM dbo.tbDeptBudget

DECLARE @SQL VARCHAR(5000)
DECLARE @ColName1 VARCHAR(50)
DECLARE @ColName2 VARCHAR(50)
DECLARE @ColName3 VARCHAR(50)
DECLARE @Year INT
DECLARE @ID INT
DECLARE @RowNum INT
SET @Year = 0
SET @ID = 1
SET @RowNum = (SELECT COUNT(0) FROM #tmpYear)
WHILE @ID <= @RowNum
BEGIN
    SET @Year = (SELECT [YEAR] FROM #tmpYear WHERE ID = @ID)    
    SET @ColName1 = 'Bduget_' + CAST(@Year AS VARCHAR(10))
    SET @ColName2 = 'Fact_' + CAST(@Year AS VARCHAR(10))
    SET @ColName3 = 'Remain_' + CAST(@Year AS VARCHAR(10))

    --增加动态列
    SET @SQL = 'ALTER TABLE #tmpResult ADD ' + @ColName1 + ' Decimal(18,2)'
              + 'ALTER TABLE #tmpResult ADD ' + @ColName2 + ' Decimal(18,2)'
              + 'ALTER TABLE #tmpResult ADD ' + @ColName3 + ' Decimal(18,2)'
    EXEC(@SQL)

    --写入动态列数据
    SET @SQL = 'UPDATE T SET ' + @ColName1 + ' = S.BudgetAmount,' + @ColName2 + ' = S.FactAmount,'+ @ColName3 + ' = S.RemainAmount '
        + ' FROM #tmpResult T INNER JOIN ( '
        + ' SELECT (DeptCode + ' + QUOTENAME('_','''') +' + ProCode) AS KeyCode,MAX(BudgetAmount)AS BudgetAmount ,MAX(FactAmount)AS FactAmount,MAX(RemainAmount)AS RemainAmount '
        + ' FROM dbo.tbDeptBudget WHERE Year= ' + CAST (@Year AS VARCHAR(10))
        + ' GROUP BY DeptCode,ProCode '
        + ') S ON T.KeyCode = S.KeyCode '

    PRINT @SQL
    EXEC(@SQL)

    SET @ID = @ID  + 1
END

--3.返回结果
SELECT * FROM #tmpResult

--4.清理临时表
IF OBJECT_ID('tempdb..#tmpYear') IS NOT NULL
BEGIN
    DROP TABLE #tmpYear
END
IF OBJECT_ID('tempdb..#tmpResult') IS NOT NULL
BEGIN
    DROP TABLE #tmpResult
END

View Code

 澳门金沙vip 15

 

澳门金沙vip 16澳门金沙vip 17

3. 测量试验数据脚本

澳门金沙vip 18澳门金沙vip 19

/*-----1.行转列的测试数据--------------------------*/
IF OBJECT_ID('tbScore') IS NOT NULL 
    DROP TABLE tbScore

GO

CREATE TABLE tbScore
    (
      姓名 VARCHAR(10) ,
      课程 VARCHAR(10) ,
      分数 INT,
      日期 DATETIME
    )
GO

INSERT  INTO tbScore VALUES  ( '张三', '语文', 74,GETDATE() )
--INSERT  INTO tbScore VALUES  ( '张三', '数学', 83 ,GETDATE() )
INSERT  INTO tbScore VALUES  ( '张三', '物理', 93 ,GETDATE() )
INSERT  INTO tbScore VALUES  ( '李四', '语文', 74 ,GETDATE() )
INSERT  INTO tbScore VALUES  ( '李四', '数学', 84 ,GETDATE() )
INSERT  INTO tbScore VALUES  ( '李四', '物理', 94 ,GETDATE() )
GO

/*-----2.列转行的测试数据--------------------------*/
IF OBJECT_ID('tbScoreNew') IS NOT NULL 
    DROP TABLE tbScoreNew

GO

CREATE TABLE tbScoreNew(
      姓名 VARCHAR(10) ,
      语文 INT,
      数学 INT,
      物理 INT,
      日期 DATETIME
    )
GO

INSERT  INTO tbScoreNew VALUES  ( '李四', 74,84,94,GETDATE() )
INSERT  INTO tbScoreNew VALUES  ( '张三', 74,83,93,GETDATE() )
GO


/*-----3.动态增加列实现行转列(模拟组内项目要求)--------------------------*/
IF OBJECT_ID('tbDeptBudget') IS NOT NULL 
    DROP TABLE tbDeptBudget

GO
--部门预算
CREATE TABLE tbDeptBudget
(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    DeptCode VARCHAR(20),--部门编码
    DeptName NVARCHAR(100), --部门名称
    ProCode VARCHAR(20),--项目编码
    ProName NVARCHAR(100),--项目名称
    Year INT, --年度
    BudgetAmount DECIMAL(18,2), --预算金额
    FactAmount DECIMAL(18,2), --实际金额
    RemainAmount DECIMAL(18,2), --剩余金额
    CreateTime DATETIME  --创建时间
)
GO

INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('人事部','010000','01','差旅费',2014,100000.00,80000.00,20000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('人事部','010000','01','差旅费',2015,110000.00,90000.00,50000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('人事部','010000','01','差旅费',2016,120000.00,100000.00,80000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('人事部','010000','02','办公用品',2015,200000.00,150000.00,10000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('人事部','010000','02','办公用品',2016,160000.00,120000.00,80000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('财务部','020000','02','办公用品',2014,50000.00,40000.00,0.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('财务部','020000','02','办公用品',2015,50000.00,50000.00,10000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('财务部','020000','02','办公用品',2016,60000.00,50000.00,40000.00,GETDATE());
INSERT INTO tbDeptBudget(DeptName,DeptCode,ProCode,ProName,YEAR,BudgetAmount,FactAmount,RemainAmount,CreateTime)
VALUES('财务部','020000','03','采购费',2016,100000.00,80000.00,60000.00,GETDATE());

View Code

澳门金沙vip, 

测量检验脚本附属类小部件

 1 USE [AdventureDB]
 2 GO
 3 /****** Object:  Table [dbo].[Score]    Script Date: 11/25/2016 4:30:50 PM ******/
 4 SET ANSI_NULLS ON
 5 GO
 6 
 7 SET QUOTED_IDENTIFIER ON
 8 GO
 9 
10 CREATE TABLE [dbo].[Score]([Name] [varchar](50) NULL,[Subject] [varchar](50) NULL,[Score] FLOAT NULL) ON [PRIMARY]
11 GO
12 
13 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Jack', N'linguistic', 65)
14 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Tom', N'linguistic', 56)
15 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Lina', N'linguistic', 84)
16 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Jack', N'Mathematics', 100)
17 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Tom', N'Mathematics', 82)
18 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Lina', N'Mathematics', 67)
19 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Jack', N'English', 82)
20 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Tom', N'English', 54)
21 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Lina', N'English', 76)
22 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'James', N'Other', 52)
23 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Tom', N'Other', 99)
24 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Lina', N'Other', 79)
25 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kobe', N'linguistic', 65)
26 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'James', N'linguistic', 76)
27 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kidd', N'linguistic', 86)
28 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'James', N'Mathematics', 70)
29 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kobe', N'Mathematics', 92)
30 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kidd', N'Mathematics', 70)
31 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kobe', N'English', 86)
32 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kidd', N'English', 85)
33 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'James', N'English', 66)
34 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Jack', N'Other', 77)
35 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kobe', N'Other', 97)
36 INSERT INTO [dbo].[Score] ([Name], [Subject], [Score]) VALUES (N'Kidd', N'Other', 93)

4. 仿照效法资料

   

 

 

View Code

澳门金沙vip 20

2.用到CASE语句询问

澳门金沙vip 21澳门金沙vip 22

 1 USE [AdventureDB]
 2 GO
 3 
 4 /****** Object:  StoredProcedure [dbo].[CaseSelect]    Script Date: 12/02/2016 00:47:02 ******/
 5 SET ANSI_NULLS ON
 6 GO
 7 
 8 SET QUOTED_IDENTIFIER ON
 9 GO
10 
11 CREATE procedure [dbo].[CaseSelect] AS
12 
13 BEGIN
14 
15    SELECT [Name],
16         SUM (case when [Subject] = 'English' then [Score] else 0 end) English,
17         SUM (case when [Subject] = 'linguistic' then [Score] else 0 end) Linguistic,
18         SUM (case when [Subject] = 'Mathematics' then [Score] else 0 end) Mathematics,
19         SUM (case when [Subject] = 'Other' then [Score] else 0 end) Other,
20         AVG ([Score]) Average
21     FROM [dbo].[score] GROUP BY [Name] ORDER BY [Name] DESC
22     
23 END
24 
25 GO

View Code

澳门金沙vip 23

3.使用PIVOT行转列

澳门金沙vip 24澳门金沙vip 25

 1 USE [AdventureDB]
 2 GO
 3 
 4 /****** Object:  StoredProcedure [dbo].[Pivot]    Script Date: 12/02/2016 01:07:27 ******/
 5 SET ANSI_NULLS ON
 6 GO
 7 
 8 SET QUOTED_IDENTIFIER ON
 9 GO
10 
11 CREATE procedure [dbo].[Pivot]
12     @NumberOfStudents int = 5
13 AS
14 
15 IF @NumberOfStudents < 1 or @NumberOfStudents > 10
16     RAISERROR('@NumberOfStudents must be between 1 and 10', 11, 1);
17 ELSE
18     SELECT top(@NumberOfStudents)
19         p.[name],
20         p.English,
21         p.linguistic,
22         p.Mathematics,
23         p.Other,
24         (p.English + p.linguistic+p.Mathematics + p.Other)/4 AS Average
25     FROM [dbo].[score] PIVOT (SUM (score) FOR [subject] IN (English,linguistic,Mathematics,Other) ) AS P
26     ORDER BY  p.[name] DESC
27     
28 RETURN;
29 
30 GO

View Code