SQL Server中动态列转行
http://www.cnblogs.com/gaizai/p/3753296.html
一.本文所涉及的内容(Contents)
- 本文所涉及的内容(Contents)
- 背景(Contexts)
- 实现代码(SQL Codes)
- 参考文献(References)
二.背景(Contexts)
其实行转列并不是一个什么新鲜的话题了,甚至已经被大家说到烂了,网上的很多例子多多少少都有些问题,所以我希望能让大家快速的看到执行的效果,所以在动态列的基础上再把表、分组字段、行转列字段、值这四个行转列固定需要的值变成真正意义的参数化,大家只需要根据自己的环境,设置参数值,马上就能看到效果了(可以直接跳转至:“参数化动态PIVOT行转列”查看具体的脚本代码)。行转列的效果图如图1所示:
三.实现代码(SQL Codes)
(一) 首先我们先创建一个测试表,往里面插入测试数据,返回表记录如图2所示:

- --创建测试表
- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestRows2Columns]') AND type in (N'U'))
- DROP TABLE [dbo].[TestRows2Columns]
- GO
- CREATE TABLE [dbo].[TestRows2Columns](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [UserName] [nvarchar](50) NULL,
- [Subject] [nvarchar](50) NULL,
- [Source] [numeric](18, 0) NULL
- ) ON [PRIMARY]
- GO
- --插入测试数据
- INSERT INTO [TestRows2Columns] ([UserName],[Subject],[Source])
- SELECT N'张三',N'语文',60 UNION ALL
- SELECT N'李四',N'数学',70 UNION ALL
- SELECT N'王五',N'英语',80 UNION ALL
- SELECT N'王五',N'数学',75 UNION ALL
- SELECT N'王五',N'语文',57 UNION ALL
- SELECT N'李四',N'语文',80 UNION ALL
- SELECT N'张三',N'英语',100
- GO
- SELECT * FROM [TestRows2Columns]

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

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

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

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

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

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

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

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

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

- --5:参数化动态PIVOT行转列
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2014.05.26>
- -- Description: <参数化动态PIVOT行转列>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- DECLARE @sql_str NVARCHAR(MAX)
- DECLARE @sql_col NVARCHAR(MAX)
- DECLARE @tableName SYSNAME --行转列表
- DECLARE @groupColumn SYSNAME --分组字段
- DECLARE @row2column SYSNAME --行变列的字段
- DECLARE @row2columnValue SYSNAME --行变列值的字段
- SET @tableName = 'TestRows2Columns'
- SET @groupColumn = 'UserName'
- SET @row2column = 'Subject'
- SET @row2columnValue = 'Source'
- --从行数据中获取可能存在的列
- SET @sql_str = N'
- SELECT @sql_col_out = ISNULL(@sql_col_out + '','','''') + QUOTENAME(['+@row2column+'])
- FROM ['+@tableName+'] GROUP BY ['+@row2column+']'
- --PRINT @sql_str
- EXEC sp_executesql @sql_str,N'@sql_col_out NVARCHAR(MAX) OUTPUT',@sql_col_out=@sql_col OUTPUT
- --PRINT @sql_col
- SET @sql_str = N'
- SELECT * FROM (
- SELECT ['+@groupColumn+'],['+@row2column+'],['+@row2columnValue+'] FROM ['+@tableName+']) p PIVOT
- (SUM(['+@row2columnValue+']) FOR ['+@row2column+'] IN ( '+ @sql_col +') ) AS pvt
- ORDER BY pvt.['+@groupColumn+']'
- --PRINT (@sql_str)
- EXEC (@sql_str)

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

- --6:带条件查询的参数化动态PIVOT行转列
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2014.05.26>
- -- Description: <参数化动态PIVOT行转列,带条件查询的参数化动态PIVOT行转列>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- DECLARE @sql_str NVARCHAR(MAX)
- DECLARE @sql_col NVARCHAR(MAX)
- DECLARE @sql_where NVARCHAR(MAX)
- DECLARE @tableName SYSNAME --行转列表
- DECLARE @groupColumn SYSNAME --分组字段
- DECLARE @row2column SYSNAME --行变列的字段
- DECLARE @row2columnValue SYSNAME --行变列值的字段
- SET @tableName = 'TestRows2Columns'
- SET @groupColumn = 'UserName'
- SET @row2column = 'Subject'
- SET @row2columnValue = 'Source'
- SET @sql_where = 'WHERE UserName = ''王五'''
- --从行数据中获取可能存在的列
- SET @sql_str = N'
- SELECT @sql_col_out = ISNULL(@sql_col_out + '','','''') + QUOTENAME(['+@row2column+'])
- FROM ['+@tableName+'] '+@sql_where+' GROUP BY ['+@row2column+']'
- --PRINT @sql_str
- EXEC sp_executesql @sql_str,N'@sql_col_out NVARCHAR(MAX) OUTPUT',@sql_col_out=@sql_col OUTPUT
- --PRINT @sql_col
- SET @sql_str = N'
- SELECT * FROM (
- SELECT ['+@groupColumn+'],['+@row2column+'],['+@row2columnValue+'] FROM ['+@tableName+']'+@sql_where+') p PIVOT
- (SUM(['+@row2columnValue+']) FOR ['+@row2column+'] IN ( '+ @sql_col +') ) AS pvt
- ORDER BY pvt.['+@groupColumn+']'
- --PRINT (@sql_str)
- EXEC (@sql_str)

(图6)
四.参考文献(References)
SQL Server中动态列转行的更多相关文章
- sql server单个字段列转行由,隔开
SELECT STUFF((SELECT ','+字段名 FROM 表名 for xml path('')),1,1,'')
- SQL Server中的GUID
GUID(Global unique identifier)全局唯一标识符,它是由网卡上的标识数字(每个网卡都有唯一的标识号)以及 CPU 时钟的唯一数字生成的的一个 16 字节的二进制值. GUID ...
- 使用CASE表达式替代SQL Server中的动态SQL
原文:使用CASE表达式替代SQL Server中的动态SQL 翻译自: http://www.mssqltips.com/sqlservertip/1455/using-the-case-expre ...
- SQL Server 行转列,列转行。多行转成一列
一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- SQL Server 行转列,列转行
一.多行转成一列(并以","隔开) 表名:A 表数据: 想要的查询结果: 查询语句: SELECT name , value = ( STUFF(( SELECT ',' + va ...
- SQL Server中Id自增列的最大Id是多少
什么是自增列 在SQL Server中可以将Id列设为自增.即无需为Id指定值,由SQL Server自动给该列赋值,每新增一列Id的值加一,初始值为1. 需要注意的是即使将原先添加的所有数据都删除, ...
- SQL Server中的标识列
一.标识列的定义以及特点 SQL Server中的标识列又称标识符列,习惯上又叫自增列. 该种列具有以下三种特点: .列的数据类型为不带小数的数值类型 .在进行插入(Insert)操作时,该列的值是由 ...
- Sql Server中判断表、列不存在则创建的方法[转]
一.Sql Server中如何判断表中某列是否存在 首先跟大家分享Sql Server中判断表中某列是否存在的两个方法,方法示例如下: 比如说要判断表A中的字段C是否存在两个方法: 第一种方法 ? ...
随机推荐
- 导入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 ...
- 图解Git命令【转】
本文转载自:https://github.com/geeeeeeeeek/git-recipes/wiki/4.1-%E5%9B%BE%E8%A7%A3Git%E5%91%BD%E4%BB%A4 此页 ...
- windows10如何安装cpu版本tensorflow
1.获取anaconda https://repo.continuum.io/archive/Anaconda3-2018.12-Windows-x86_64.exe (这个版本内置python3.7 ...
- eclipse中下载maven插件解决办法
https://blog.csdn.net/qq_30546099/article/details/71195446 解决Eclipse Maven插件的最佳方案 https://www.cnblog ...
- maven clean 异常问题
当使用`mvn clean`,报`maven… Failed to clean project: Failed to delete ..`时,如果你觉得这个文件删除成功或失败没有关系,可以使用如下命令 ...
- install ros-indigo-ecl-build
-- ==> add_subdirectory(bp_smart_charging/bp_dock_drive) CMake Warning at /opt/ros/indigo/share/c ...
- Angel 实现FFM 一、对于Angel 和分布式机器学习的简单了解
Angel是腾讯开源的一个分布式机器学习框架.是一个PS模式的分布式机器学习框架. https://github.com/Angel-ML/angel 这是github地址. 我了解的分布式机器学 ...
- Mysql语句转义
String sqlStr = "SELECT * FROM t_sys_dic WHERE idPath LIKE" + "'" + "/19/20 ...
- 记一次加载js不全报错的原因总结
1.运营商广告 dns 劫持2.浏览器本身并发数3.服务器配置keepAliveTimeout=04.加载文件过大5.
- vue-router详解
对于单页应用,官方提供了vue-router进行路由跳转的处理,本篇主要也是基于其官方文档写作而成. 安装 基于传统,我更喜欢采用npm包的形式进行安装. npm install vue-router ...