本文翻译自:Efficiently convert rows to columns in sql server

I'm looking for an efficient way to convert rows to columns in SQL server, I heard that PIVOT is not very fast, and I need to deal with lot of records. 我正在寻找一种在SQL Server中将行转换为列的有效方法,听说PIVOT速度不是很快,并且我需要处理很多记录。

This is my example: 这是我的示例:

   -------------------------------| Id | Value  | ColumnName    |-------------------------------| 1  | John   | FirstName     || 2  | 2.4    | Amount        || 3  | ZH1E4A | PostalCode    || 4  | Fork   | LastName      || 5  | 857685 | AccountNumber |-------------------------------

This is my result: 这是我的结果:

---------------------------------------------------------------------
| FirstName  |Amount|   PostalCode   |   LastName  |  AccountNumber |
---------------------------------------------------------------------
| John       | 2.4  |   ZH1E4A       |   Fork      |  857685        |
---------------------------------------------------------------------

How can I build the result? 如何建立结果?


#1楼

参考:https://stackoom.com/question/1440I/在SQL-Server中将行有效地转换为列


#2楼

There are several ways that you can transform data from multiple rows into columns. 您可以通过多种方式将数据从多行转换为列。

Using PIVOT 使用PIVOT

In SQL Server you can use the PIVOT function to transform the data from rows to columns: 在SQL Server中,可以使用PIVOT函数将数据从行转换为列:

select Firstname, Amount, PostalCode, LastName, AccountNumber
from
(select value, columnnamefrom yourtable
) d
pivot
(max(value)for columnname in (Firstname, Amount, PostalCode, LastName, AccountNumber)
) piv;

See Demo . 参见演示 。

Pivot with unknown number of columnnames columnnames数量未知的数据透视

If you have an unknown number of columnnames that you want to transpose, then you can use dynamic SQL: 如果要转置的columnnames数量未知,则可以使用动态SQL:

DECLARE @cols AS NVARCHAR(MAX),@query  AS NVARCHAR(MAX)select @cols = STUFF((SELECT ',' + QUOTENAME(ColumnName) from yourtablegroup by ColumnName, idorder by idFOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')set @query = N'SELECT ' + @cols + N' from (select value, ColumnNamefrom yourtable) xpivot (max(value)for ColumnName in (' + @cols + N')) p 'exec sp_executesql @query;

See Demo . 参见演示 。

Using an aggregate function 使用聚合函数

If you do not want to use the PIVOT function, then you can use an aggregate function with a CASE expression: 如果您不想使用PIVOT函数,则可以将聚合函数与CASE表达式一起使用:

selectmax(case when columnname = 'FirstName' then value end) Firstname,max(case when columnname = 'Amount' then value end) Amount,max(case when columnname = 'PostalCode' then value end) PostalCode,max(case when columnname = 'LastName' then value end) LastName,max(case when columnname = 'AccountNumber' then value end) AccountNumber
from yourtable

See Demo . 参见演示 。

Using multiple joins 使用多个联接

This could also be completed using multiple joins, but you will need some column to associate each of the rows which you do not have in your sample data. 也可以使用多个联接来完成此操作,但是您将需要一些列来关联示例数据中没有的每一行。 But the basic syntax would be: 但基本语法为:

select fn.value as FirstName,a.value as Amount,pc.value as PostalCode,ln.value as LastName,an.value as AccountNumber
from yourtable fn
left join yourtable aon fn.somecol = a.somecoland a.columnname = 'Amount'
left join yourtable pcon fn.somecol = pc.somecoland pc.columnname = 'PostalCode'
left join yourtable lnon fn.somecol = ln.somecoland ln.columnname = 'LastName'
left join yourtable anon fn.somecol = an.somecoland an.columnname = 'AccountNumber'
where fn.columnname = 'Firstname'

#3楼

as pivoting data is still a hot one I decided to add something form me. 由于数据透视仍然很热门,因此我决定添加一些数据。 This is rather a method than just a single script but gives you much more possibilities. 这是一种方法,而不仅仅是一个脚本,但是为您提供了更多的可能性。 First of all There are 3 scripts you need to deploy: 1) User defined TABLE type [ ColumnActionList ] -> holds data as parameter 2) SP [ proc_PivotPrepare ] -> prepares our data 3) SP [ proc_PivotExecute ] -> execute the script 首先,需要部署3个脚本:1)用户定义的TABLE类型[ ColumnActionList ]->将数据作为参数保存2)SP [ proc_PivotPrepare ]->准备我们的数据3)SP [ proc_PivotExecute ]->执行脚本

    CREATE TYPE [dbo].[ColumnActionList] AS TABLE([ID] [smallint] NOT NULL,[ColumnName] [nvarchar](128) NOT NULL,[Action] [nchar](1) NOT NULL);
GOCREATE PROCEDURE [dbo].[proc_PivotPrepare] (@DB_Name        nvarchar(128),@TableName      nvarchar(128))AS---------------------------------------------------------------------------------------------------------| Author: Bartosz----------------------------------------------------------------------------------------------------SELECT @DB_Name = ISNULL(@DB_Name,db_name())DECLARE @SQL_Code nvarchar(max)DECLARE @MyTab TABLE (ID smallint identity(1,1), [Column_Name] nvarchar(128), [Type] nchar(1), [Set Action SQL] nvarchar(max));SELECT @SQL_Code        =   'SELECT [<| SQL_Code |>] = '' '' '+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''-----| Declare user defined type [ID] / [ColumnName] / [PivotAction] '' '+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''DECLARE @ColumnListWithActions ColumnActionList;'''+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''-----| Set [PivotAction] (''''S'''' as default) to select dimentions and values '' '+ 'UNION ALL '+ 'SELECT ''-----|'''+ 'UNION ALL '+ 'SELECT ''-----| ''''S'''' = Stable column || ''''D'''' = Dimention column || ''''V'''' = Value column '' '+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''INSERT INTO  @ColumnListWithActions VALUES ('' + CAST( ROW_NUMBER() OVER (ORDER BY [NAME]) as nvarchar(10)) + '', '' + '''''''' + [NAME] + ''''''''+ '', ''''S'''');'''+ 'FROM [' + @DB_Name + '].sys.columns  '+ 'WHERE object_id = object_id(''[' + @DB_Name + ']..[' + @TableName + ']'') '+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''-----| Execute sp_PivotExecute with parameters: columns and dimentions and main table name'' '+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '+ 'UNION ALL '+ 'SELECT ''EXEC [dbo].[sp_PivotExecute] @ColumnListWithActions, ' + '''''' + @TableName + '''''' + ';'''+ 'UNION ALL '+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '                            EXECUTE SP_EXECUTESQL @SQL_Code;GO
CREATE PROCEDURE [dbo].[proc_PivotExecute]
(
@ColumnListWithActions  ColumnActionList ReadOnly
,@TableName                     nvarchar(128)
)
AS
--#######################################################################################################################
--###| Author: Bartosz
--#######################################################################################################################--#######################################################################################################################
--###| Step 1 - Select our user-defined-table-variable into temp table
--#######################################################################################################################IF OBJECT_ID('tempdb.dbo.#ColumnListWithActions', 'U') IS NOT NULL DROP TABLE #ColumnListWithActions;
SELECT * INTO #ColumnListWithActions FROM @ColumnListWithActions;--#######################################################################################################################
--###| Step 2 - Preparing lists of column groups as strings:
--#######################################################################################################################DECLARE @ColumnName                     nvarchar(128)
DECLARE @Destiny                        nchar(1)DECLARE @ListOfColumns_Stable           nvarchar(max)
DECLARE @ListOfColumns_Dimension    nvarchar(max)
DECLARE @ListOfColumns_Variable     nvarchar(max)
--############################
--###| Cursor for List of Stable Columns
--############################DECLARE ColumnListStringCreator_S CURSOR FOR
SELECT      [ColumnName]
FROM        #ColumnListWithActions
WHERE       [Action] = 'S'
OPEN ColumnListStringCreator_S;
FETCH NEXT FROM ColumnListStringCreator_S
INTO @ColumnNameWHILE @@FETCH_STATUS = 0BEGINSELECT @ListOfColumns_Stable = ISNULL(@ListOfColumns_Stable, '') + ' [' + @ColumnName + '] ,';FETCH NEXT FROM ColumnListStringCreator_S INTO @ColumnNameENDCLOSE ColumnListStringCreator_S;
DEALLOCATE ColumnListStringCreator_S;--############################
--###| Cursor for List of Dimension Columns
--############################DECLARE ColumnListStringCreator_D CURSOR FOR
SELECT      [ColumnName]
FROM        #ColumnListWithActions
WHERE       [Action] = 'D'
OPEN ColumnListStringCreator_D;
FETCH NEXT FROM ColumnListStringCreator_D
INTO @ColumnNameWHILE @@FETCH_STATUS = 0BEGINSELECT @ListOfColumns_Dimension = ISNULL(@ListOfColumns_Dimension, '') + ' [' + @ColumnName + '] ,';FETCH NEXT FROM ColumnListStringCreator_D INTO @ColumnNameENDCLOSE ColumnListStringCreator_D;
DEALLOCATE ColumnListStringCreator_D;--############################
--###| Cursor for List of Variable Columns
--############################DECLARE ColumnListStringCreator_V CURSOR FOR
SELECT      [ColumnName]
FROM        #ColumnListWithActions
WHERE       [Action] = 'V'
OPEN ColumnListStringCreator_V;
FETCH NEXT FROM ColumnListStringCreator_V
INTO @ColumnNameWHILE @@FETCH_STATUS = 0BEGINSELECT @ListOfColumns_Variable = ISNULL(@ListOfColumns_Variable, '') + ' [' + @ColumnName + '] ,';FETCH NEXT FROM ColumnListStringCreator_V INTO @ColumnNameENDCLOSE ColumnListStringCreator_V;
DEALLOCATE ColumnListStringCreator_V;SELECT @ListOfColumns_Variable      = LEFT(@ListOfColumns_Variable, LEN(@ListOfColumns_Variable) - 1);
SELECT @ListOfColumns_Dimension = LEFT(@ListOfColumns_Dimension, LEN(@ListOfColumns_Dimension) - 1);
SELECT @ListOfColumns_Stable            = LEFT(@ListOfColumns_Stable, LEN(@ListOfColumns_Stable) - 1);--#######################################################################################################################
--###| Step 3 - Preparing table with all possible connections between Dimension columns excluding NULLs
--#######################################################################################################################
DECLARE @DIM_TAB TABLE ([DIM_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO @DIM_TAB
SELECT [DIM_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName] FROM #ColumnListWithActions WHERE [Action] = 'D';DECLARE @DIM_ID smallint;
SELECT      @DIM_ID = 1;DECLARE @SQL_Dimentions nvarchar(max);IF OBJECT_ID('tempdb.dbo.##ALL_Dimentions', 'U') IS NOT NULL DROP TABLE ##ALL_Dimentions; SELECT @SQL_Dimentions      = 'SELECT ID = ROW_NUMBER() OVER (ORDER BY ' + @ListOfColumns_Dimension + '), ' + @ListOfColumns_Dimension+ ' INTO ##ALL_Dimentions '+ ' FROM (SELECT DISTINCT' + @ListOfColumns_Dimension + ' FROM  ' + @TableName+ ' WHERE ' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = @DIM_ID) + ' IS NOT NULL ';SELECT @DIM_ID = @DIM_ID + 1;WHILE @DIM_ID <= (SELECT MAX([DIM_ID]) FROM @DIM_TAB)BEGINSELECT @SQL_Dimentions = @SQL_Dimentions + 'AND ' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = @DIM_ID) +  ' IS NOT NULL ';SELECT @DIM_ID = @DIM_ID + 1;ENDSELECT @SQL_Dimentions   = @SQL_Dimentions + ' )x';EXECUTE SP_EXECUTESQL  @SQL_Dimentions;--#######################################################################################################################
--###| Step 4 - Preparing table with all possible connections between Stable columns excluding NULLs
--#######################################################################################################################
DECLARE @StabPos_TAB TABLE ([StabPos_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO @StabPos_TAB
SELECT [StabPos_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName] FROM #ColumnListWithActions WHERE [Action] = 'S';DECLARE @StabPos_ID smallint;
SELECT      @StabPos_ID = 1;DECLARE @SQL_MainStableColumnTable nvarchar(max);IF OBJECT_ID('tempdb.dbo.##ALL_StableColumns', 'U') IS NOT NULL DROP TABLE ##ALL_StableColumns; SELECT @SQL_MainStableColumnTable       = 'SELECT ID = ROW_NUMBER() OVER (ORDER BY ' + @ListOfColumns_Stable + '), ' + @ListOfColumns_Stable+ ' INTO ##ALL_StableColumns '+ ' FROM (SELECT DISTINCT' + @ListOfColumns_Stable + ' FROM  ' + @TableName+ ' WHERE ' + (SELECT [ColumnName] FROM @StabPos_TAB WHERE [StabPos_ID] = @StabPos_ID) + ' IS NOT NULL ';SELECT @StabPos_ID = @StabPos_ID + 1;WHILE @StabPos_ID <= (SELECT MAX([StabPos_ID]) FROM @StabPos_TAB)BEGINSELECT @SQL_MainStableColumnTable = @SQL_MainStableColumnTable + 'AND ' + (SELECT [ColumnName] FROM @StabPos_TAB WHERE [StabPos_ID] = @StabPos_ID) +  ' IS NOT NULL ';SELECT @StabPos_ID = @StabPos_ID + 1;ENDSELECT @SQL_MainStableColumnTable    = @SQL_MainStableColumnTable + ' )x';EXECUTE SP_EXECUTESQL  @SQL_MainStableColumnTable;--#######################################################################################################################
--###| Step 5 - Preparing table with all options ID
--#######################################################################################################################DECLARE @FULL_SQL_1 NVARCHAR(MAX)
SELECT @FULL_SQL_1 = ''DECLARE @i smallintIF OBJECT_ID('tempdb.dbo.##FinalTab', 'U') IS NOT NULL DROP TABLE ##FinalTab; SELECT @FULL_SQL_1 = 'SELECT t.*, dim.[ID] '+ ' INTO ##FinalTab '+   'FROM ' + @TableName + ' t '+   'JOIN ##ALL_Dimentions dim '+   'ON t.' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = 1) + ' = dim.' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = 1);SELECT @i = 2                               WHILE @i <= (SELECT MAX([DIM_ID]) FROM @DIM_TAB)BEGINSELECT @FULL_SQL_1 = @FULL_SQL_1 + ' AND t.' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = @i) + ' = dim.' + (SELECT [ColumnName] FROM @DIM_TAB WHERE [DIM_ID] = @i)SELECT @i = @i +1END
EXECUTE SP_EXECUTESQL @FULL_SQL_1--#######################################################################################################################
--###| Step 6 - Selecting final data
--#######################################################################################################################
DECLARE @STAB_TAB TABLE ([STAB_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO @STAB_TAB
SELECT [STAB_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName]
FROM #ColumnListWithActions WHERE [Action] = 'S';DECLARE @VAR_TAB TABLE ([VAR_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO @VAR_TAB
SELECT [VAR_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName]
FROM #ColumnListWithActions WHERE [Action] = 'V';DECLARE @y smallint;
DECLARE @x smallint;
DECLARE @z smallint;DECLARE @FinalCode nvarchar(max)SELECT @FinalCode = ' SELECT ID1.*'SELECT @y = 1WHILE @y <= (SELECT MAX([ID]) FROM ##FinalTab)BEGINSELECT @z = 1WHILE @z <= (SELECT MAX([VAR_ID]) FROM @VAR_TAB)BEGINSELECT @FinalCode = @FinalCode +    ', [ID' + CAST((@y) as varchar(10)) + '.' + (SELECT [ColumnName] FROM @VAR_TAB WHERE [VAR_ID] = @z) + '] =  ID' + CAST((@y + 1) as varchar(10)) + '.' + (SELECT [ColumnName] FROM @VAR_TAB WHERE [VAR_ID] = @z)SELECT @z = @z + 1ENDSELECT @y = @y + 1ENDSELECT @FinalCode = @FinalCode + ' FROM ( SELECT * FROM ##ALL_StableColumns)ID1';SELECT @y = 1WHILE @y <= (SELECT MAX([ID]) FROM ##FinalTab)BEGINSELECT @x = 1SELECT @FinalCode = @FinalCode + ' LEFT JOIN (SELECT ' +  @ListOfColumns_Stable + ' , ' + @ListOfColumns_Variable + ' FROM ##FinalTab WHERE [ID] = ' + CAST(@y as varchar(10)) + ' )ID' + CAST((@y + 1) as varchar(10))  + ' ON 1 = 1' WHILE @x <= (SELECT MAX([STAB_ID]) FROM @STAB_TAB)BEGINSELECT @FinalCode = @FinalCode + ' AND ID1.' + (SELECT [ColumnName] FROM @STAB_TAB WHERE [STAB_ID] = @x) + ' = ID' + CAST((@y+1) as varchar(10)) + '.' + (SELECT [ColumnName] FROM @STAB_TAB WHERE [STAB_ID] = @x)SELECT @x = @x +1ENDSELECT @y = @y + 1ENDSELECT * FROM ##ALL_Dimentions;
EXECUTE SP_EXECUTESQL @FinalCode;
--#######################################################################################################################

From executing the first query (by passing source DB and table name) you will get a pre-created execution query for the second SP, all you have to do is define is the column from your source: + Stable + Value (will be used to concentrate values based on that) + Dim (column you want to use to pivot by) 通过执行第一个查询(通过传递源数据库和表名称),您将获得针对第二个SP的预先创建的执行查询,您所要做的就是定义源中的列:+稳定+值(将使用以基于该值集中值)+ Dim(您要用来作为透视依据的列)

Names and datatypes will be defined automatically! 名称和数据类型将自动定义!

I cant recommend it for any production environments but does the job for adhoc BI requests. 我不能将其推荐给任何生产环境,但可以满足即席BI请求的要求。

在SQL Server中将行有效地转换为列相关推荐

  1. sql server 中将datetime类型转换为date,或者time

    sql server 中将datetime类型转换为date,或者time 2008年01月14日 星期一 14:46 这个转换总是记不住,用到的时候就找,现贴上来,以备查用. datetime类型转 ...

  2. 关于SQL Server中将数值类型转换为字符串的问题

    今天在把一些数据导入到SQL Server的时候遇到有个列被导入成float类型,而我实际需要的是varchar类型,所以要进行类型转换,转换时遇到了一点问题,所以写这篇博客记录一下. SQL Ser ...

  3. MSSQL-Scripter,一个新的生成T-SQL脚本的SQL Server命令行工具

    这里向大家介绍一个新的生成T-SQL脚本的SQL Server命令行工具:mssql-scripter.它支持在SQL Server.Azure SQL DB以及Azure SQL DW中为数据库生成 ...

  4. SQL Server命令行

    本文来源于网络收集,Mark一下. 1.登陆 osql -S localhost -U sa -P 123456 T-SQL 即 Transact-SQL,是 SQL 在 Microsoft SQL ...

  5. sql 如何设置行级锁_如何使用SQL Server 2016行级安全性过滤和阻止数据访问

    sql 如何设置行级锁 SQL Server 2016 came with many new features and enhancements for existing ones, that con ...

  6. 图解sql server 命令行工具sqlcmd的使用

    一 操作实例 安装了sql server后此工具已经有了: 以sa登录: 打个命令,没反映: 可执行操作系统命令:加上!!即可: 查看帮助: 再打命令,也没反映:查询结果不显示: 要加上go,才行: ...

  7. 42000[SQL Server]ORDER BY子句中的列无效,该列没有包含在聚合函数或GROUP BY 子句

    [Err] 42000 - [SQL Server]ORDER BY 子句中的列 "t_xxx.inputDate" 无效,因为该列没有包含在聚合函数或 GROUP BY 子 错误 ...

  8. sql server合并行_合并SQL Server复制参数化的行筛选器问题

    sql server合并行 In this article we will discuss about SQL Server Merge Replication Parameterized row f ...

  9. SQL Server 2008行数据和页数据压缩解密

    SQL Server的性能主要取决于磁盘I/O效率,提高I/O效率某种程序上就意味着提高性能.SQL Server 2008提供了数据压缩功能来提高磁盘I/O. 数据压缩意味着减小数据的有磁盘占用量, ...

最新文章

  1. word中用EndNote引用文献,之后再打开插入新文献,格式显示错误的问题
  2. C-Lodop回调函数的触发
  3. Spring boot中最大连接数、最大线程数与最大等待数在生产中的异常场景
  4. 如何通过属性给实体赋值
  5. session一些基本的东西
  6. input标签中使输入文本向右偏移像素解决方案(亲测有效)
  7. Lucene 的索引文件锁原理
  8. 企业监控服务器Cacti、nagios服务器
  9. 大数据分析四大分析要素
  10. 最简单解决jpa自动生成表后字段乱序问题
  11. jQuery超酷轻量级响应式lightbox插件
  12. win7蓝屏0x0000003b解决教程
  13. [LOJ6437][计算几何]PKUSC2018:PKUSC
  14. 物联网终端安全系列(之四) -- 终端安全方案之SIM卡篇
  15. 蓝色大气的交替导航菜单
  16. 联合国发布AI报告:自动化和AI对亚洲有巨大影响
  17. context.getContentResolver().query()详细用法详解
  18. 【CodeForces 1260E --- Tournament】
  19. 乌班图服务器清理log文件,定时清除ubuntu下log日志文件
  20. 使用VB.net将PNG图片转成icon类型图标文件

热门文章

  1. Android开发:图文分析 Handler通信机制 的工作原理
  2. 第四周项目五-用递归方法求解(输出Fibnacci序列的第20个数)
  3. Storm和MR及Spark Streaming的区别
  4. (0104)iOS开发之在Mac上用Charles给iPhone抓包
  5. Docker:容器的四种网络类型 [十三]
  6. git reset --hard xxxxxxx
  7. sql_INSERT DELETE
  8. 20171218-编程语言的介绍
  9. Java设计模式学习06——静态代理与动态代理(转)
  10. HDU-5723 Abandoned country