T-SQL 动态数据透视
Posted
技术标签:
【中文标题】T-SQL 动态数据透视【英文标题】:T-SQL dynamic pivot 【发布时间】:2012-08-25 23:55:37 【问题描述】:好的,我有一张像这样的表
ItemID | ColumnName | Value
1 | name | Peter
1 | phone | 12345678
1 | email | peter@host.com
2 | name | John
2 | phone | 87654321
2 | email | john@host.com
3 | name | Sarah
3 | phone | 55667788
3 | email | sarah@host.com
现在我需要把它变成这样:
ItemID | name | phone | email
1 | Peter | 12345678 | peter@host.com
2 | John | 87654321 | john@host.com
3 | Sarah | 55667788 | sarah@host.com
我一直在查看动态枢轴示例,但似乎无法将它们融入我的场景。
谁能帮忙?
【问题讨论】:
我在您的数据中看不到数据透视。您在第一个块中以一种奇怪的方式列出了常规列名和值,通常在第二个块中。 如果第一个块代表您的实际数据,那么为什么它会像这样存储而不是标准化? 为什么需要动态 PIVOT 来处理这些数据?这可以通过静态 PIVOT 来实现(检查我的答案)。是因为您希望 ColumnName 的值不是姓名、电话和电子邮件吗? 是的,列名和列数会改变。我应该提到这一点。 数据未标准化的相同原因。 【参考方案1】:看看下面的例子
CREATE TABLE #Table (
ID INT,
ColumnName VARCHAR(250),
Value VARCHAR(250)
)
INSERT INTO #Table SELECT 1,'name','Peter'
INSERT INTO #Table SELECT 1,'phone','12345678'
INSERT INTO #Table SELECT 1,'email','peter@host.com'
INSERT INTO #Table SELECT 2,'name','John'
INSERT INTO #Table SELECT 2,'phone','87654321'
INSERT INTO #Table SELECT 2,'email','john@host.com'
INSERT INTO #Table SELECT 3,'name','Sarah'
INSERT INTO #Table SELECT 3,'phone','55667788'
INSERT INTO #Table SELECT 3,'email','sarah@host.com'
---I assumed your tablename as TESTTABLE---
DECLARE @cols NVARCHAR(2000)
DECLARE @query NVARCHAR(4000)
SELECT @cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT
'],[' + t.ColumnName
FROM #Table AS t
--ORDER BY '],[' + t.ID
FOR XML PATH('')
), 1, 2, '') + ']'
SELECT @cols
SET @query = N'SELECT ID,'+ @cols +' FROM
(SELECT t1.ID,t1.ColumnName , t1.Value FROM #Table AS t1) p
PIVOT (MAX([Value]) FOR ColumnName IN ( '+ @cols +' ))
AS pvt;'
EXECUTE(@query)
DROP TABLE #Table
【讨论】:
非常感谢,这正是我想要的!【参考方案2】:试试这个:
SQL Server 2005+
;with
cte_name as(select * from <table> where ColumnName='name'),
cte_phone as(select * from <table> where ColumnName='phone'),
cte_email as(select * from <table> where ColumnName='email')
select n.ItemID,n.Value [Name],p.Value [Phone],e.Value [Email]
from cte_name n
join cte_phone p
on n.ItemID=p.ItemID
join cte_email e
on n.ItemID=e.ItemID
SQL Fiddle Demo
【讨论】:
【参考方案3】:您不需要动态数据透视表,因为它将是一张不同的表格。只需执行以下操作:
name phone email
---------------------------------
Peter
123456
peter@host.com
查看SQL fiddle
SELECT DISTINCT u.ItemID, n.Value as 'name', p.Value as 'phone', e.Value as 'email'
FROM UserData u
INNER JOIN(
SELECT ItemID, Value
FROM UserData WHERE ColumnName = 'name') n ON n.ItemID = u.ItemID
INNER JOIN(
SELECT ItemID, Value
FROM UserData WHERE ColumnName = 'phone') p ON p.ItemID = u.ItemID
INNER JOIN(
SELECT ItemID, Value
FROM UserData WHERE ColumnName = 'email') e ON e.ItemID = u.ItemID
【讨论】:
问题是 ColumnNames 是动态的。它们的名称和列数都会有所不同。【参考方案4】:这是我用于联系人列表的查询 :)
SELECT *
FROM
(
SELECT Contact_Id AS CT
, [Age]
, [Sex]
, [State]
, [Country]
, [Keyword]
, [Married]
, [Kids]
, [Car]
FROM
(SELECT c.PropertyName
, c.ValueString
, c.Contact_Id
FROM
ContactProfiles c) AS ctp
PIVOT (max(ctp.ValueString) FOR PropertyName IN ([Age], [Sex], [State], [Country], [Keyword], [Married], [Kids], [Car])) AS PivotTable
) AS pvt
WHERE
pvt.[Age] > 18
AND (pvt.[State] = 'CA' OR pvt.[State] = 'NY')
AND pvt.[Sex] = 'F'
--*AND pvt.[Keyword] LIKE '%B;%'
AND pvt.[Married] = 'True'
AND pvt.[Kids] > 0
【讨论】:
【参考方案5】:你试过了吗:
SELECT ItemID, name, phone, email
FROM
(SELECT [ItemID] ,[ColumnName] ,[Value] FROM Item) Item
PIVOT (MAX(Value) FOR ColumnName IN (name, phone, email) ) as pvt
【讨论】:
问题是 ColumnNames 是动态的。它们的名称和列数都会有所不同。以上是关于T-SQL 动态数据透视的主要内容,如果未能解决你的问题,请参考以下文章