MSSQL纵列转横列

   在工作中我们一般会遇到将纵列转横列的需求,具体代码:

1.建表

CREATE TABLE [dbo].[AcrossChangeEndLong](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [Subject] [nvarchar](50) NOT NULL,
    [Score] [int] NOT NULL,
 CONSTRAINT [PK_AcrossChangeEndLong] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[AcrossChangeEndLong] ON 

GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (1, N'张三', N'语文', 100)
GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (3, N'李四', N'语文', 80)
GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (4, N'张三', N'英语', 80)
GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (5, N'李四', N'英语', 50)
GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (6, N'张三', N'数学', 55)
GO
INSERT [dbo].[AcrossChangeEndLong] ([Id], [Name], [Subject], [Score]) VALUES (7, N'李四', N'数学', 34)
GO
SET IDENTITY_INSERT [dbo].[AcrossChangeEndLong] OFF
GO
ALTER TABLE [dbo].[AcrossChangeEndLong] ADD  CONSTRAINT [DF_AcrossChangeEndLong_Score]  DEFAULT ((0)) FOR [Score]
GO

2.具体SQL

SELECT  Name AS '姓名',
        MAX(CASE [Subject]
              WHEN '语文' THEN Score
              ELSE 0
            END) AS '语文' ,
        MAX(CASE [Subject]
              WHEN '英语' THEN Score
              ELSE 0
            END) AS '英语' ,
        MAX(CASE [Subject]
              WHEN '数学' THEN Score
              ELSE 0
            END) AS '数学'
FROM    dbo.AcrossChangeEndLong
GROUP BY Name ORDER BY Name

如果到时候增加了科目,比如增加了化学,这时候为了再次修改,我们可以弄成动态的(根据列自动增加),这里使用的是动态拼接SQL,会根据科目的增加而增加列,具体SQL如下

DECLARE @sql VARCHAR(8000)
SET @sql = 'SELECT [Name],'   
SELECT  @sql = @sql + 'SUM(CASE [Subject] WHEN ''' + [Subject]
        + ''' THEN [Score] ELSE 0 END) AS ''' + [Subject] + ''','
FROM    ( SELECT DISTINCT
                    [Subject]
          FROM      dbo.AcrossChangeEndLong
        ) AS a     
SELECT  @sql = LEFT(@sql, LEN(@sql) - 1)
        + ' FROM [AcrossChangeEndLong] GROUP BY [Name]'   
PRINT ( @sql )
EXEC(@sql)

 另外在SQL Server 2005之后有了一个专门的PIVOT 和 UNPIVOT 关系运算符做行列之间的转换

 注意:这种不能用于 eg: CASE [Subject] WHEN '数学' THEN Score ELSE 0 END 如果Then 后面是1(统计的时候会用到)而不是具体字段的时候,使用会报错,具体SQL如下

SELECT  *
FROM    ( SELECT    Name AS '姓名',
                    Subject ,
                    Score
          FROM      dbo.AcrossChangeEndLong
        ) p PIVOT ( MAX(Score) FOR Subject IN ( [数学], [英语], [语文] ) ) AS pvt
ORDER BY pvt.姓名

 使用Pivot动态拼接SQL:

DECLARE @sql_str VARCHAR(MAX)
DECLARE @sql_col VARCHAR(MAX)
SELECT  @sql_col = ISNULL(@sql_col + ',', '') + QUOTENAME([Subject])
FROM    dbo.AcrossChangeEndLong
GROUP BY [Subject]
SET @sql_str = '
SELECT * FROM (
    SELECT [Name],[Subject],[Score] FROM [AcrossChangeEndLong]) p PIVOT 
    (SUM([Score]) FOR [Subject] IN ( ' + @sql_col + ') ) AS pvt 
ORDER BY pvt.[Name]'
PRINT ( @sql_str )
EXEC (@sql_str)

具体效果:  

 

扩展:可能我们需要加一个统计行,可以用UNION ALL连接 上一个表的结果【可以将结果插入临时表】,再用函数SUM求和各个列

原文地址:https://www.cnblogs.com/zuqing/p/4878728.html