Dan*_*gan 6 sql pivot sql-server-2008 pivot-without-aggregate
我知道你有多个主题涉及到这一点.但是,我找不到满足我需求的.我需要(按需)将深度表数据透视到宽输出表.这里的问题是我不能使用Pivot的聚合,因为它会占用输出中需要的响应.我已经找到了解决方案,但我认为这不是最好的,因为它需要无数的左连接才能工作.我已将所有尝试和说明包括在内如下:
-- Sql Server 2008 db.
-- Deep table structure (not subject to modification) contains name/value pairs with a userId as
-- foreign key. In many cases there can be MORE THAN ONE itemValue given by the user for the
-- itemName such as if asked their race, can answer White + Hispanic, etc. Each response is stored
-- as a seperate record - this cannot currently be changed.
-- Goal: pivot deep data to wide while also compressing result
-- set down. Account for all items per userId, and duplicating
-- column values (rather than show nulls) as applicable
-- Sample table to store some data of both single and multiple responses
DECLARE @testTable AS TABLE(userId int, itemName varchar(50), itemValue varchar(255))
INSERT INTO @testTable
SELECT 1, 'q01', '1-q01 Answer'
UNION SELECT 1, 'q02', '1-q02 Answer'
UNION SELECT 1, 'q03', '1-q03 Answer 1'
UNION SELECT 1, 'q03', '1-q03 Answer 2'
UNION SELECT 1, 'q03', '1-q03 Answer 3'
UNION SELECT 1, 'q04', '1-q04 Answer'
UNION SELECT 1, 'q05', '1-q05 Answer'
UNION SELECT 2, 'q01', '2-q01 Answer'
UNION SELECT 2, 'q02', '2-q02 Answer'
UNION SELECT 2, 'q03', '2-q03 Answer 1'
UNION SELECT 2, 'q03', '2-q03 Answer 2'
UNION SELECT 2, 'q04', '2-q04 Answer'
UNION SELECT 2, 'q05', '2-q05 Answer'
SELECT 'Raw Data'
SELECT * FROM @TestTable
SELECT 'Using Pivot - shows aggregate result of itemValue per itemName - eats others'
; WITH Data AS (
SELECT
[userId]
, [itemName]
, [itemValue]
FROM
@testTable
)
SELECT
[userId]
, [q02]
, [q03]
, [q05]
FROM
Data
PIVOT
(
MIN(itemValue) -- Aggregate function eats needed values.
FOR itemName in ([q02], [q03], [q05])
) AS PivotTable
SELECT 'Aggregate with Grouping - Causes Null Values'
SELECT
DISTINCT userId
,[q02] = Max(CASE WHEN itemName = 'q02' THEN itemValue END)
,[q03] = Max(CASE WHEN itemName = 'q03' THEN itemValue END)
,[q05] = Max(CASE WHEN itemName = 'q05' THEN itemValue END)
FROM
@testTable
WHERE
itemName in ('q02', 'q03', 'q05') -- Makes it a hair quicker
GROUP BY
userId -- If by userId only, it only gives 1 row PERIOD = BAD!!
, [itemName]
, [itemValue]
SELECT 'Multiple Left Joins - works properly but bad if pivoting 175 columns or so'
; WITH Data AS (
SELECT
userId
,[itemName]
,[itemValue]
FROM
@testTable
WHERE
itemName in ('q02', 'q03', 'q05') -- Makes it a hair quicker
)
SELECT
DISTINCT s1.userId
,[q02] = s2.[itemValue]
,[q03] = s3.[itemValue]
,[q05] = s5.[itemValue]
FROM
Data s1
LEFT JOIN Data s2
ON s2.userId = s1.userId
AND s2.[itemName] = 'q02'
LEFT JOIN Data s3
ON s3.userId = s1.userId
AND s3.[itemName] = 'q03'
LEFT JOIN Data s5
ON s5.userId = s1.userId
AND s5.[itemName] = 'q05'
因此,底层查询是唯一一个(到目前为止)执行我需要它做的事情,但是当我使用实际项目名称进行转动时,LEFT JOIN将失控并导致性能问题.任何建议表示赞赏.
; 将 SRData 作为 (
SELECT——仅查询该块中的单个响应项
[用户身份]
, [q01]
, [q02]
, [q04]
, [q05]
从
@测试表
枢
(
MIN(项目值)
FOR itemName in ([q01], [q02], [q04], [q05])
) AS 数据透视表
)
选择
sr.[用户 ID]
,老先生。[q01]
,老先生。[q02]
, [q03] = mr03.[项目值]
,老先生。[q04]
,老先生。[q05]
, [q06] = mr06.[项目值]
从
SR数据SR
LEFT JOIN @testTable mr03 ON mr03.userId = sr.userId AND mr03.itemName = 'q03' -- Muli 响应 q03
LEFT JOIN @testTable mr06 ON mr06.userId = sr.userId AND mr06.itemName = 'q06' -- Muli 响应 q06