在sql server中高效地将行转换为列

在sql server中高效地将行转换为列,sql,sql-server,sql-server-2008,pivot,Sql,Sql Server,Sql Server 2008,Pivot,我正在寻找一种在SQL server中将行转换为列的有效方法,我听说PIVOT速度不是很快,我需要处理大量记录 这是我的例子: ------------------------------- | Id | Value | ColumnName | ------------------------------- | 1 | John | FirstName | | 2 | 2.4 | Amount | | 3 | Z

我正在寻找一种在SQL server中将行转换为列的有效方法,我听说PIVOT速度不是很快,我需要处理大量记录

这是我的例子:

   -------------------------------
   | Id | Value  | ColumnName    |
   -------------------------------
   | 1  | John   | FirstName     |
   | 2  | 2.4    | Amount        |
   | 3  | ZH1E4A | PostalCode    |
   | 4  | Fork   | LastName      |
   | 5  | 857685 | AccountNumber |
   -------------------------------
这是我的结果:

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

如何生成结果?

有几种方法可以将数据从多行转换为列

使用枢轴 在SQL Server中,可以使用PIVOT函数将数据从行转换为列:

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

列名称数目未知的透视 如果要转置的列名数量未知,则可以使用动态SQL:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(ColumnName) 
                    from yourtable
                    group by ColumnName, id
                    order by id
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = N'SELECT ' + @cols + N' from 
             (
                select value, ColumnName
                from yourtable
            ) x
            pivot 
            (
                max(value)
                for ColumnName in (' + @cols + N')
            ) p '

exec sp_executesql @query;

使用聚合函数 如果不想使用PIVOT函数,则可以使用带有大小写表达式的聚合函数:

select
  max(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

使用多个联接 这也可以使用多个联接来完成,但是您需要一些列来关联示例数据中没有的每一行。但基本语法是:

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 a
  on fn.somecol = a.somecol
  and a.columnname = 'Amount'
left join yourtable pc
  on fn.somecol = pc.somecol
  and pc.columnname = 'PostalCode'
left join yourtable ln
  on fn.somecol = ln.somecol
  and ln.columnname = 'LastName'
left join yourtable an
  on fn.somecol = an.somecol
  and an.columnname = 'AccountNumber'
where fn.columnname = 'Firstname'

这是一种方法,而不仅仅是一个脚本,但为您提供了更大的灵活性

首先,有3个对象:

用户定义的表类型[ColumnActionList]->将数据保存为 参数 SP[proc_PivotPrepare]->准备我们的数据 SP[proc_PivotExecute]->执行脚本 将类型[dbo].[ColumnActionList]创建为表 [ID][smallint]不为空, [ColumnName]nvarchar不为空, [操作]nchar不为空 ; 去

通过传递source DB和table name执行第一个查询,您将获得第二个SP的预创建执行查询,您只需定义源中的列: +马厩 +值将用于在此基础上集中值 +要用于轴心旋转的Dim列

名称和数据类型将自动定义

我不能推荐它用于任何生产环境,但它可以用于临时BI请求

请试一试

CREATE TABLE pvt (Present int, [Absent] int);
GO
INSERT INTO pvt VALUES (10,40);
GO
--Unpivot the table.
SELECT Code, Value
FROM 
   (SELECT Present, Absent
   FROM pvt) p
UNPIVOT
   (Value FOR Code IN 
      (Present, [Absent])
)AS unpvt;
GO

DROP TABLE pvt

+1 . . . 但在上一个示例中,您可以使用交叉连接而不是左连接,因为每个子查询返回一行。我需要构建一个动态查询,因为我不知道行数。让我们讨论一下如何转换一个包含10000.000百万的表records@tbag如果行数未知,则必须使用动态sql,但请注意,转换数百万行是没有效率的。我无法使用视图进行转换,那么使用TFV如何?这就是为什么我在寻找一个有效的解决方案。@tbag Dynamic SQL不能用于视图或表值函数,它必须用于存储过程中,直到找不到存储过程“dbo.sp_PivotIt”为止。有什么建议吗?@DarXyde sory我必须混合2个版本,请重新编译并再试一次Hanks Bartosz,设法使用了您脚本中的一些想法并完成了我已经想到的,但是,感谢您更新它:。我本应该想更改这一行,但老实说,我认为这是一个您已经忘记的存储过程,它不是系统中的默认值或类似的东西。我会给它一个运行时,我再次接近该项目,并在这里更新!仍然是错误的SP名称,但现在我知道了错误所在,很容易修复:SP_Pivot_Execute更改为proc_Pivot Execute.@DarXyde-谢谢,您发现了这一点-这一问题已经解决了-这对已经接受的答案有何改进?
CREATE TABLE pvt (Present int, [Absent] int);
GO
INSERT INTO pvt VALUES (10,40);
GO
--Unpivot the table.
SELECT Code, Value
FROM 
   (SELECT Present, Absent
   FROM pvt) p
UNPIVOT
   (Value FOR Code IN 
      (Present, [Absent])
)AS unpvt;
GO

DROP TABLE pvt