今天我的同事要求我将数据从垂直临时表转换为水平表。我的意思是将行转换为列。我使用了PIVOT并解决了它。但是如果数据字段重复,我遇到了移动数据的麻烦。
以下是我正在处理的测试数据:
CREATE TABLE STAGING
(
ENTITYID INT,
PROPERTYNAME VARCHAR(25),
PROPERTYVALUE VARCHAR(25)
)
INSERT INTO STAGING VALUES (1, 'NAME', 'DONNA')
INSERT INTO STAGING VALUES (1, 'SPOUSE', 'HENRY')
INSERT INTO STAGING VALUES (1, 'CHILD', 'JACK')
INSERT INTO STAGING VALUES (2, 'CHILD', 'KAYALA')
我使用PIVOT将行数据显示为列:
SELECT * FROM
(SELECT ENTITYID, PROPERTYNAME, PROPERTYVALUE FROM STAGING) AS T
PIVOT (MAX(PROPERTYVALUE) FOR PROPERTYNAME IN (NAME, SPOUSE, CHILD)) AS T2
输出结果为:
ENTITYID NAME SPOUSE CHILD
1 DONNA HENRY JACK
2 NULL NULL KAYALA
但他希望输出类似于:
ENTITYID NAME SPOUSE CHILD CHILD
1 DONNA HENRY JACK KAYALA
底线是登台表中可以有多个CHILD属性。我们需要考虑这一点并将所有儿童移到专栏。
这可能吗?
答案 0 :(得分:6)
您可以在属性名称中添加行号,以便您执行所需操作:
SELECT * FROM
(
SELECT ENTITYID
, PROPERTYNAME = PROPERTYNAME + CAST(ROW_NUMBER() OVER(PARTITION BY ENTITYID, PROPERTYNAME ORDER BY PROPERTYVALUE) AS VARCHAR(5))
,PROPERTYVALUE
FROM #STAGING
) AS T
PIVOT (MAX(PROPERTYVALUE) FOR PROPERTYNAME IN (NAME1, SPOUSE1, CHILD1, CHILD2, CHILD3, CHILD4, CHILD5)) AS T2
我在这里假设ENTITYID将孩子与父母联系在一起,即同一个人的所有孩子的ENTITYID为1,但你的例子显示Kayala为2。
这是一个演示:SQL Fiddle
如果你只想要CHILD字段的数字,你可以把它放在:
PROPERTYNAME = CASE WHEN PROPERTYNAME LIKE '%CHILD%' THEN PROPERTYNAME + CAST(ROW_NUMBER() OVER(PARTITION BY ENTITYID, PROPERTYNAME ORDER BY PROPERTYVALUE) AS VARCHAR(5)) ELSE PROPERTYNAME END
然后从IN()语句中的其他字段中删除该数字。
奖金问题 - 动态执行以上操作: 我们不想假设人们只有一个配偶或2.3个孩子,所以我们动态地做了一点:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
SELECT @cols = STUFF((SELECT ',' + PROPERTYNAME
FROM (SELECT DISTINCT PROPERTYNAME = PROPERTYNAME + CAST(ROW_NUMBER() OVER(PARTITION BY ENTITYID, PROPERTYNAME ORDER BY PROPERTYVALUE) AS VARCHAR(5))
FROM STAGING )sub
ORDER BY CASE WHEN PROPERTYNAME LIKE '%NAME%' THEN 1
WHEN PROPERTYNAME LIKE '%SPOUSE%' THEN 2
WHEN PROPERTYNAME LIKE '%CHILD%' THEN 3
ELSE 4
END
,RIGHT(PROPERTYNAME,1)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET @query = 'SELECT * FROM
(
SELECT ENTITYID, PROPERTYNAME = PROPERTYNAME + CAST(ROW_NUMBER() OVER(PARTITION BY ENTITYID, PROPERTYNAME ORDER BY PROPERTYVALUE) AS VARCHAR(5)),PROPERTYVALUE
FROM STAGING
) AS T
PIVOT (MAX(PROPERTYVALUE) FOR PROPERTYNAME IN ('+@cols+')) AS T2
'
EXEC(@query)
注意:订购仅适用于配偶1-9和子女1-9,您可以根据需要进行调整,但无论如何都是任意的。
答案 1 :(得分:0)
如果您不需要显示实体ID,请正确查看您的问题,您需要输出: -
ENTITYID NAME SPOUSE CHILD CHILD
1 DONNA HENRY JACK KAYALA(This one is entityId=2)
所以不正确,那么即使你想要这样的结果:
NAME SPOUSE CHILD CHILD
DONNA HENRY JACK KAYALA
SELECT * FROM (SELECT PROPERTYNAME, PROPERTYVALUE FROM STAGING) AS T PIVOT (MAX(PROPERTYVALUE) FOR PROPERTYNAME IN (NAME, SPOUSE, CHILD)) AS T2