Я знаю, что у вас есть несколько тем, касающихся этого. Но я не нашел ни одного, который отвечал бы моим потребностям. Мне нужно (по запросу) развернуть данные глубокой таблицы для широкой выходной таблицы. Проблема в том, что я не могу использовать агрегат с 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 ВЫЙДЕТ из-под контроля и вызовет проблемы с производительностью, когда я используйте фактические имена элементов для поворота. Любые рекомендации приветствуются.