http://www.cnblogs.com/gaizai/p/3753296.html

一.本文所涉及的内容(Contents)

  1. 本文所涉及的内容(Contents)
  2. 背景(Contexts)
  3. 实现代码(SQL Codes)
    1. 方法一:使用拼接SQL,静态列字段;
    2. 方法二:使用拼接SQL,动态列字段;
    3. 方法三:使用PIVOT关系运算符,静态列字段;
    4. 方法四:使用PIVOT关系运算符,动态列字段;
    5. 扩展阅读一:参数化表名、分组列、行转列字段、字段值;
    6. 扩展阅读二:在前面的基础上加入条件过滤;
  4. 参考文献(References)
  5. 二.背景(Contexts)

      其实行转列并不是一个什么新鲜的话题了,甚至已经被大家说到烂了,网上的很多例子多多少少都有些问题,所以我希望能让大家快速的看到执行的效果,所以在动态列的基础上再把表、分组字段、行转列字段、值这四个行转列固定需要的值变成真正意义的参数化,大家只需要根据自己的环境,设置参数值,马上就能看到效果了(可以直接跳转至:“参数化动态PIVOT行转列”查看具体的脚本代码)。行转列的效果图如图1所示:

三.实现代码(SQL Codes)

(一) 首先我们先创建一个测试表,往里面插入测试数据,返回表记录如图2所示:

  1. --创建测试表
  2. IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestRows2Columns]') AND type in (N'U'))
  3. DROP TABLE [dbo].[TestRows2Columns]
  4. GO
  5. CREATE TABLE [dbo].[TestRows2Columns](
  6. [Id] [int] IDENTITY(1,1) NOT NULL,
  7. [UserName] [nvarchar](50) NULL,
  8. [Subject] [nvarchar](50) NULL,
  9. [Source] [numeric](18, 0) NULL
  10. ) ON [PRIMARY]
  11. GO
  12.  
  13. --插入测试数据
  14. INSERT INTO [TestRows2Columns] ([UserName],[Subject],[Source])
  15. SELECT N'张三',N'语文',60 UNION ALL
  16. SELECT N'李四',N'数学',70 UNION ALL
  17. SELECT N'王五',N'英语',80 UNION ALL
  18. SELECT N'王五',N'数学',75 UNION ALL
  19. SELECT N'王五',N'语文',57 UNION ALL
  20. SELECT N'李四',N'语文',80 UNION ALL
  21. SELECT N'张三',N'英语',100
  22. GO
  23.  
  24. SELECT * FROM [TestRows2Columns]

(图2:样本数据)

(二) 先以静态的方式实现行转列,效果如图3所示:

  1. --1:静态拼接行转列
  2. SELECT [UserName],
  3. SUM(CASE [Subject] WHEN '数学' THEN [Source] ELSE 0 END) AS '[数学]',
  4. SUM(CASE [Subject] WHEN '英语' THEN [Source] ELSE 0 END) AS '[英语]',
  5. SUM(CASE [Subject] WHEN '语文' THEN [Source] ELSE 0 END) AS '[语文]'
  6. FROM [TestRows2Columns]
  7. GROUP BY [UserName]
  8. GO

(图3:样本数据)

(三) 接着以动态的方式实现行转列,这是使用拼接SQL的方式实现的,所以它适用于SQL Server 2000以上的数据库版本,执行脚本返回的结果如图2所示;

  1. --2:动态拼接行转列
  2. DECLARE @sql VARCHAR(8000)
  3. SET @sql = 'SELECT [UserName],'
  4. SELECT @sql = @sql + 'SUM(CASE [Subject] WHEN '''+[Subject]+''' THEN [Source] ELSE 0 END) AS '''+QUOTENAME([Subject])+''','
  5. FROM (SELECT DISTINCT [Subject] FROM [TestRows2Columns]) AS a
  6. SELECT @sql = LEFT(@sql,LEN(@sql)-1) + ' FROM [TestRows2Columns] GROUP BY [UserName]'
  7. PRINT(@sql)
  8. EXEC(@sql)
  9. GO

(四) 在SQL Server 2005之后有了一个专门的PIVOT 和 UNPIVOT 关系运算符做行列之间的转换,下面是静态的方式实现的,实现效果如图4所示:

  1. --3:静态PIVOT行转列
  2. SELECT *
  3. FROM ( SELECT [UserName] ,
  4. [Subject] ,
  5. [Source]
  6. FROM [TestRows2Columns]
  7. ) p PIVOT
  8. ( SUM([Source]) FOR [Subject] IN ( [数学],[英语],[语文] ) ) AS pvt
  9. ORDER BY pvt.[UserName];
  10. GO

(图4)

(五) 把上面静态的SQL基础上进行修改,这样就不用理会记录里面存储了什么,需要转成什么列名的问题了,脚本如下,效果如图4所示:

  1. --4:动态PIVOT行转列
  2. DECLARE @sql_str VARCHAR(8000)
  3. DECLARE @sql_col VARCHAR(8000)
  4. SELECT @sql_col = ISNULL(@sql_col + ',','') + QUOTENAME([Subject]) FROM [TestRows2Columns] GROUP BY [Subject]
  5. SET @sql_str = '
  6. SELECT * FROM (
  7. SELECT [UserName],[Subject],[Source] FROM [TestRows2Columns]) p PIVOT
  8. (SUM([Source]) FOR [Subject] IN ( '+ @sql_col +') ) AS pvt
  9. ORDER BY pvt.[UserName]'
  10. PRINT (@sql_str)
  11. EXEC (@sql_str)

(六) 也许很多人到了上面一步就够了,但是你会发现,当别人拿到你的代码,需要不断的修改成他自己环境中表名、分组列、行转列字段、字段值这几个参数,逻辑如图5所示,所以,我继续对上面的脚本进行修改,你只要设置自己的参数就可以实现行转列了,效果如图4所示:

  1. --5:参数化动态PIVOT行转列
  2. -- =============================================
  3. -- Author: <听风吹雨>
  4. -- Create date: <2014.05.26>
  5. -- Description: <参数化动态PIVOT行转列>
  6. -- Blog: <http://www.cnblogs.com/gaizai/>
  7. -- =============================================
  8. DECLARE @sql_str NVARCHAR(MAX)
  9. DECLARE @sql_col NVARCHAR(MAX)
  10. DECLARE @tableName SYSNAME --行转列表
  11. DECLARE @groupColumn SYSNAME --分组字段
  12. DECLARE @row2column SYSNAME --行变列的字段
  13. DECLARE @row2columnValue SYSNAME --行变列值的字段
  14. SET @tableName = 'TestRows2Columns'
  15. SET @groupColumn = 'UserName'
  16. SET @row2column = 'Subject'
  17. SET @row2columnValue = 'Source'
  18.  
  19. --从行数据中获取可能存在的列
  20. SET @sql_str = N'
  21. SELECT @sql_col_out = ISNULL(@sql_col_out + '','','''') + QUOTENAME(['+@row2column+'])
  22. FROM ['+@tableName+'] GROUP BY ['+@row2column+']'
  23. --PRINT @sql_str
  24. EXEC sp_executesql @sql_str,N'@sql_col_out NVARCHAR(MAX) OUTPUT',@sql_col_out=@sql_col OUTPUT
  25. --PRINT @sql_col
  26.  
  27. SET @sql_str = N'
  28. SELECT * FROM (
  29. SELECT ['+@groupColumn+'],['+@row2column+'],['+@row2columnValue+'] FROM ['+@tableName+']) p PIVOT
  30. (SUM(['+@row2columnValue+']) FOR ['+@row2column+'] IN ( '+ @sql_col +') ) AS pvt
  31. ORDER BY pvt.['+@groupColumn+']'
  32. --PRINT (@sql_str)
  33. EXEC (@sql_str)

(图5)

(七) 在实际的运用中,我经常遇到需要对基础表的数据进行筛选后再进行行转列,那么下面的脚本将满足你这个需求,效果如图6所示:

  1. --6:带条件查询的参数化动态PIVOT行转列
  2. -- =============================================
  3. -- Author: <听风吹雨>
  4. -- Create date: <2014.05.26>
  5. -- Description: <参数化动态PIVOT行转列,带条件查询的参数化动态PIVOT行转列>
  6. -- Blog: <http://www.cnblogs.com/gaizai/>
  7. -- =============================================
  8. DECLARE @sql_str NVARCHAR(MAX)
  9. DECLARE @sql_col NVARCHAR(MAX)
  10. DECLARE @sql_where NVARCHAR(MAX)
  11. DECLARE @tableName SYSNAME --行转列表
  12. DECLARE @groupColumn SYSNAME --分组字段
  13. DECLARE @row2column SYSNAME --行变列的字段
  14. DECLARE @row2columnValue SYSNAME --行变列值的字段
  15. SET @tableName = 'TestRows2Columns'
  16. SET @groupColumn = 'UserName'
  17. SET @row2column = 'Subject'
  18. SET @row2columnValue = 'Source'
  19. SET @sql_where = 'WHERE UserName = ''王五'''
  20.  
  21. --从行数据中获取可能存在的列
  22. SET @sql_str = N'
  23. SELECT @sql_col_out = ISNULL(@sql_col_out + '','','''') + QUOTENAME(['+@row2column+'])
  24. FROM ['+@tableName+'] '+@sql_where+' GROUP BY ['+@row2column+']'
  25. --PRINT @sql_str
  26. EXEC sp_executesql @sql_str,N'@sql_col_out NVARCHAR(MAX) OUTPUT',@sql_col_out=@sql_col OUTPUT
  27. --PRINT @sql_col
  28.  
  29. SET @sql_str = N'
  30. SELECT * FROM (
  31. SELECT ['+@groupColumn+'],['+@row2column+'],['+@row2columnValue+'] FROM ['+@tableName+']'+@sql_where+') p PIVOT
  32. (SUM(['+@row2columnValue+']) FOR ['+@row2column+'] IN ( '+ @sql_col +') ) AS pvt
  33. ORDER BY pvt.['+@groupColumn+']'
  34. --PRINT (@sql_str)
  35. EXEC (@sql_str)

(图6)

四.参考文献(References)

使用 PIVOT 和 UNPIVOT

SQL Server中动态列转行的更多相关文章

  1. sql server单个字段列转行由,隔开

    SELECT STUFF((SELECT ','+字段名 FROM 表名 for xml path('')),1,1,'')

  2. SQL Server中的GUID

    GUID(Global unique identifier)全局唯一标识符,它是由网卡上的标识数字(每个网卡都有唯一的标识号)以及 CPU 时钟的唯一数字生成的的一个 16 字节的二进制值. GUID ...

  3. 使用CASE表达式替代SQL Server中的动态SQL

    原文:使用CASE表达式替代SQL Server中的动态SQL 翻译自: http://www.mssqltips.com/sqlservertip/1455/using-the-case-expre ...

  4. SQL Server 行转列,列转行。多行转成一列

    一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...

  5. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  6. SQL Server 行转列,列转行

    一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...

  7. SQL Server中Id自增列的最大Id是多少

    什么是自增列 在SQL Server中可以将Id列设为自增.即无需为Id指定值,由SQL Server自动给该列赋值,每新增一列Id的值加一,初始值为1. 需要注意的是即使将原先添加的所有数据都删除, ...

  8. SQL Server中的标识列

    一.标识列的定义以及特点 SQL Server中的标识列又称标识符列,习惯上又叫自增列. 该种列具有以下三种特点: .列的数据类型为不带小数的数值类型 .在进行插入(Insert)操作时,该列的值是由 ...

  9. Sql Server中判断表、列不存在则创建的方法[转]

    一.Sql Server中如何判断表中某列是否存在 首先跟大家分享Sql Server中判断表中某列是否存在的两个方法,方法示例如下: 比如说要判断表A中的字段C是否存在两个方法: 第一种方法  ? ...

随机推荐

  1. 导入tensorflow:ImportError: libcublas.so.9.0: cannot open shared object file: No such file or director【转】

    本文转载自:https://blog.csdn.net/ksws0292756/article/details/80034086 版权声明:本文为博主原创文章,转载请一定附上博主原文链接,并署名转自Z ...

  2. 图解Git命令【转】

    本文转载自:https://github.com/geeeeeeeeek/git-recipes/wiki/4.1-%E5%9B%BE%E8%A7%A3Git%E5%91%BD%E4%BB%A4 此页 ...

  3. windows10如何安装cpu版本tensorflow

    1.获取anaconda https://repo.continuum.io/archive/Anaconda3-2018.12-Windows-x86_64.exe (这个版本内置python3.7 ...

  4. eclipse中下载maven插件解决办法

    https://blog.csdn.net/qq_30546099/article/details/71195446 解决Eclipse Maven插件的最佳方案 https://www.cnblog ...

  5. maven clean 异常问题

    当使用`mvn clean`,报`maven… Failed to clean project: Failed to delete ..`时,如果你觉得这个文件删除成功或失败没有关系,可以使用如下命令 ...

  6. install ros-indigo-ecl-build

    -- ==> add_subdirectory(bp_smart_charging/bp_dock_drive) CMake Warning at /opt/ros/indigo/share/c ...

  7. Angel 实现FFM 一、对于Angel 和分布式机器学习的简单了解

    Angel是腾讯开源的一个分布式机器学习框架.是一个PS模式的分布式机器学习框架. https://github.com/Angel-ML/angel   这是github地址. 我了解的分布式机器学 ...

  8. Mysql语句转义

    String sqlStr = "SELECT * FROM t_sys_dic WHERE idPath LIKE" + "'" + "/19/20 ...

  9. 记一次加载js不全报错的原因总结

    1.运营商广告 dns 劫持2.浏览器本身并发数3.服务器配置keepAliveTimeout=04.加载文件过大5.

  10. vue-router详解

    对于单页应用,官方提供了vue-router进行路由跳转的处理,本篇主要也是基于其官方文档写作而成. 安装 基于传统,我更喜欢采用npm包的形式进行安装. npm install vue-router ...