SQL中的数据透视表

时间:2019-06-17 11:10:19

标签: sql-server tsql

我在处理数据表方面遇到问题:

我该如何转换:

您是否足够友善地给我提示(不是完整的代码)怎么做?我真的不知道我应该从哪里开始(我不知道这是否是典型的枢轴旋转)

+------+------+--------+----------+-----------+-----+
| ColI | Col2 | Month  | Turnover | Provision | Fee |
+------+------+--------+----------+-----------+-----+
|  123 | Asdf | 201810 |    10000 |      100  | 0,1 |
|  123 | Asdf | 201811 |    20000 |       200 | 0,2 |
|  123 | Asdf | 201812 |    30000 |       300 | 0,3 |
+------+------+--------+----------+-----------+-----+

对此:

+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+
| ColI | Col2 | Turnover20810 | Provision201810 | Fee201810  | Turnover20811 | Provision201811 | Fee201811  | Turnover20812 | Provision201812 | Fee201812 |
+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+
|  123 | Asdf |         10000 |            100  |        0,1 |         20000 |             200 |        0,2 |         30000 |             300 |       0,3 |
+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+

谢谢!

3 个答案:

答案 0 :(得分:3)

假设每个ColI, Col2组最多只有三个记录,那么我们可以尝试在ROW_NUMBER的帮助下进行数据透视:

WITH cte AS (
    SELECT *,
        ROW_NUMBER() OVER (PARTITION BY ColI, Col2 ORDER BY Month) rn
    FROM yourTable
)

SELECT
    ColI,
    Col2,
    MAX(CASE WHEN rn = 1 THEN Turnover END) AS Turnover1,
    MAX(CASE WHEN rn = 1 THEN Provision END) AS Provision1,
    MAX(CASE WHEN rn = 1 THEN Fee END) AS Fee1,
    MAX(CASE WHEN rn = 2 THEN Turnover END) AS Turnover2,
    MAX(CASE WHEN rn = 2 THEN Provision END) AS Provision2,
    MAX(CASE WHEN rn = 2 THEN Fee END) AS Fee2,
    MAX(CASE WHEN rn = 3 THEN Turnover END) AS Turnover3,
    MAX(CASE WHEN rn = 3 THEN Provision END) AS Provision3,
    MAX(CASE WHEN rn = 3 THEN Fee END) AS Fee3
FROM cte
GROUP BY
    ColI,
    Col2;

请注意,我并没有硬性规定更具体的列名,以使查询尽可能通用。例如,也许可能还有另一个ColI, Col2组,它们的三个月时间会有所不同。

答案 1 :(得分:2)

通过使用动态Sql

IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
;WITH CTE (ColI , Col2 , Month  , Turnover , Provision , Fee )
AS
(
SELECT 123 , 'Asdf' , 201810 ,    10000 ,100  ,'0,1' UNION ALL 
SELECT 123 , 'Asdf' , 201811 ,    20000 ,200 , '0,2' UNION ALL 
SELECT 123 , 'Asdf' , 201812 ,    30000 ,300 , '0,3' 
)
SELECT ColI , Col2,Turnover , Provision , Fee,MixedCol,Reqcol , ROW_NUMBER()OVER(ORDER BY (SELECT NULL)) AS Seq
INTO #Temp 
FROM CTE 
CROSS APPLY (VALUES (CONCAT('Turnover','_',[Month]),CAST(Turnover AS VARCHAR(20))),
                    (CONCAT('Provision','_',[Month]),CAST(Provision AS VARCHAR(20))),
                    (CONCAT('Fee','_',[Month]),CAST(Fee AS VARCHAR(20)))
            )DT  (MixedCol,Reqcol)

DECLARE  @Sql nvarchar(max),
         @DynamicColumn nvarchar(max),
         @MaxDynamicColumn nvarchar(max)

SELECT @DynamicColumn = STUFF((SELECT  ', '+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))
FROM #TEMP ORDER BY Seq  FOR XML PATH ('')),1,1,'') 

SELECT @MaxDynamicColumn = STUFF((SELECT  ', '+'MAX('+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))+') AS '+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))
FROM #TEMP ORDER BY Seq  FOR XML PATH ('')),1,1,'') 

SET @Sql=' SELECT  ColI , Col2,'+ @MaxDynamicColumn+'
            FROM
            (
            SELECT * FROM #TEMP
            )AS src
            PIVOT 
            (
            MAX(Reqcol) FOR [MixedCol] IN ('+@DynamicColumn+')
            ) AS Pvt
            GROUP BY ColI , Col2 '
EXEC (@Sql)
PRINT @Sql

答案 2 :(得分:0)

Q:“ ...给我提示(不是完整的代码)如何执行此操作”

A:此示例具有表的动态转置。你可以试试看取消旋转原始表格并转置。

CREATE table #tbl (
    color varchar(10), Paul int, John int, Tim int, Eric int);
insert #tbl select 
    'Red' ,1 ,5 ,1 ,3 union all select
    'Green' ,8 ,4 ,3 ,5 union all select
    'Blue' ,2 ,2 ,9 ,1;

select * FROM #tbl

--1) Transpose. Example without dynamic code. You create list of fields in query
select *
from #tbl
unpivot (value for name in ([Paul],[John],[Tim],[Eric])) up
pivot (max(value) for color in ([Blue],[Green],[Red])) p


--2) Transpose. Example with dynamic code, without names of fields.
DECLARE @cols NVARCHAR(MAX), @query NVARCHAR(MAX), @rows NVARCHAR(MAX)='';
-- XML with all values
SET @cols = STUFF(
                 (
                     SELECT DISTINCT
                            ','+QUOTENAME(T.Color)  -- Name of first column
                     FROM #tbl T FOR XML PATH(''), TYPE
                 ).value('.', 'nvarchar(max)'), 1, 1, '');

SELECT @rows=@rows+','+QUOTENAME(Name) 
FROM 
(SELECT Name,ROW_NUMBER() OVER(ORDER BY column_id) AS 'RowNum' 
FROM tempdb.sys.Columns 
WHERE Object_ID = OBJECT_ID('tempdb..#tbl') 
) AS A WHERE A.RowNum>1
SET @rows=STUFF(@rows,1,1,'')

SET @query='SELECT *
from #tbl
unpivot (value for name in ('+@rows+')) up
pivot (max(value) for color in ('+@Cols+')) p'

EXEC (@query)