在SQL Server中将行转换为N列

时间:2019-05-15 05:48:57

标签: sql-server tsql

我需要将此数据集转换为行

ID  year    reading writing spelling
33087   7   625 620 686
33087   8   544 560 541
33205   7   559 572 497
33205   8   599 560 612
33902   7   500 484 464
33902   8   607 560 686

对此:

ID  year    reading writing spelling year   reading writing spelling 
33087   7   625     620     686      8      544     560     541
33205   7   559     572     497      8      599     560     612
33902   7   500     484     464      8      607     560     686

这是我的代码:

select * from 
(select ID,year,reading 
       from #Table1 NP 
JOIN #table2 CS  ON CS.Id = NP.ID
) as  src
PIVOT
(
sum(reading) for year in ([7],[8])
) as piv 

我不确定如何将其余行放入列中。

3 个答案:

答案 0 :(得分:0)

我建议使用条件聚合

DECLARE @tbl TABLE(ID INT, [year] INT, reading INT, writing INT, spelling INT);
INSERT INTO @tbl VALUES
     (33087,7,625,620,686)
    ,(33087,8,544,560,541)
    ,(33205,7,559,572,497)
    ,(33205,8,599,560,612)
    ,(33902,7,500,484,464)
    ,(33902,8,607,560,686);

-查询:

SELECT t.ID
      ,MAX(CASE WHEN t.[year]=7 THEN t.[year] END) AS year_1
      ,MAX(CASE WHEN t.[year]=7 THEN t.reading END) AS reading_1
      ,MAX(CASE WHEN t.[year]=7 THEN t.writing END) AS writing_1
      ,MAX(CASE WHEN t.[year]=7 THEN t.spelling END) AS spelling_1

      ,MAX(CASE WHEN t.[year]=8 THEN t.[year] END) AS year_2
      ,MAX(CASE WHEN t.[year]=8 THEN t.reading END) AS reading_2
      ,MAX(CASE WHEN t.[year]=8 THEN t.writing END) AS writing_2
      ,MAX(CASE WHEN t.[year]=8 THEN t.spelling END) AS spellingg_

      --add more blocks if needed
FROM @tbl t
GROUP BY t.ID;

PIVOT仅限于一列。对于您的情况,您想一次“透视”几列。如果每个ID和年份多于一行,则此方法可提供对计算/汇总数据方式的最大控制。
另一个优点:动态创建非常容易。在这种情况下,您将必须调查数据,找到发生的年份并每年创建一个数据块。然后执行该语句。

另一种方法是条件加入

WITH IDsOnly AS
(
SELECT t.ID
FROM @tbl t
GROUP BY t.ID
)
SELECT IDsOnly.ID
      ,A.[year] AS year_1,A.reading AS reading_1,A.writing AS writing_1,A.spelling AS spelling_1
      ,B.[year] AS year_2,B.reading AS reading_2,B.writing AS writing_2,B.spelling AS spelling_2
FROM IDsOnly
LEFT JOIN(SELECT * FROM @tbl t7 WHERE t7.[year]=7) AS A ON IDsOnly.ID=A.ID
LEFT JOIN(SELECT * FROM @tbl t7 WHERE t7.[year]=8) AS B ON IDsOnly.ID=B.ID;
--Add more joins if needed...

答案 1 :(得分:0)

使用自我加入,我们可以得到结果,请尝试

;WITH CTE(ID ,[year],reading, writing, spelling)
AS
(
SELECT 33087,7,625,620,686 UNION ALL
SELECT 33087,8,544,560,541 UNION ALL
SELECT 33205,7,559,572,497 UNION ALL
SELECT 33205,8,599,560,612 UNION ALL
SELECT 33902,7,500,484,464 UNION ALL
SELECT 33902,8,607,560,686      
)
SELECT i.ID ,i.[year],i.reading, i.writing, i.spelling,
            o.[year],o.reading, o.writing, o.spelling
FROM CTE i
INNER JOIN CTE o 
    ON i.ID = o.ID
WHERE i.[year] =7 
    AND o.[year] =8

结果

ID      year    reading writing spelling    year    reading writing spelling
-----------------------------------------------------------------------------
33087   7         625    620      686         8       544      560    541
33205   7         559    572      497         8       599      560    612
33902   7         500    484      464         8       607      560    686

答案 2 :(得分:0)

此代码会将每个ID的数据排列在一行中。这些列将按年份排序,并且每个ID的每年都将列在下面。如果ID的年份为空,则将用NULL值填充。在结果列中只会列出数据集中出现的年份。

DECLARE @sql AS NVARCHAR(MAX)
DECLARE @pc AS NVARCHAR(20)
DECLARE @column_list AS NVARCHAR(MAX) 

SELECT  @pc = CONVERT(NVARCHAR, PIVOT_CODE),
        @column_list = COALESCE(@column_list + ',', '') + ' year' + @pc + ', reading' + @pc + ', writing' +@pc + ', spelling' + @pc
FROM (    
    SELECT DISTINCT Year AS PIVOT_CODE FROM YourTable 
) AS DistYears
ORDER BY PIVOT_CODE

SET @sql = '
;WITH p AS (
    SELECT ID,''year'' + CAST(year AS NVARCHAR(10)) AS Col, year AS Val FROM YourTable
    UNION ALL
    SELECT ID,''reading'' + CAST(year AS NVARCHAR(10)) AS Col, reading AS Val FROM YourTable
    UNION ALL
    SELECT ID,''writing'' + CAST(year AS NVARCHAR(10)) AS Col, writing AS Val FROM YourTable
    UNION ALL
    SELECT ID,''spelling'' + CAST(year AS NVARCHAR(10)) AS Col, spelling AS Val FROM YourTable
)
SELECT ID, ' + @column_list + '
FROM p
PIVOT (
    MAX(Val)
    FOR Col IN (
        ' + @column_list + '
    )
) AS pvt
ORDER BY ID'

EXEC(@sql)