在sql server中高效地将行转换为列
我正在寻找一种在SQL server中将行转换为列的有效方法,我听说PIVOT速度不是很快,我需要处理大量记录 这是我的例子:在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
-------------------------------
| 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