zoukankan      html  css  js  c++  java
  • 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求和各个列

  • 相关阅读:
    Importing csv data file in SQLite3
    【北京】【高级爬虫开发工程师、高级网页分析工程师】知名上市互联网公司招聘【猎头】
    介绍一个C++的ORM工具ODB(一)
    基础c练习
    virtualenv中文文档放出,请雅正
    navicat sqlite使用了一种wine的方式来支持linux平台,
    之前 传闻已经的djblets竟是reviewboard团队整的
    在HTML5 Web SQL中使用ORM工具 前端开发 e800
    本来想注册个51cto的blog
    Portable way to get file size (in bytes) in shell?
  • 原文地址:https://www.cnblogs.com/zuqing/p/4878728.html
Copyright © 2011-2022 走看看