【问题标题】:Pivoting an sql server table透视 sql server 表
【发布时间】:2016-06-08 09:07:23
【问题描述】:

如何使用 SQL 查询将 SQL Server 表 meterdata 转换为 Result_Table?

MeterData 表存储功率和频率,主键(meterno, date, timeblock),meterno 列有变量号。的价值观。

MeterData 表:

meterno date      timeblock power   frequency       
--------------------------------------------------
89      1-Apr-16    1       500       50.02     
89      1-Apr-16    2       100       49.99     
90      1-Apr-16    1       200       50.02     
90      1-Apr-16    2       300       49.89     

Result_Table

date    timeblock   89_power 90_power   89_frequency 90_frequency   
1-Apr-16    1       500      200        50.02       50.02   
1-Apr-16    2       100      300        49.99       49.89

为简单起见,我们假设meterno 列已固定编号。值说(89,90)。我正在尝试以下查询,但没有得到结果。有人可以编辑查询,以便输出是上面的 Results_Table。另外最好请使用数据透视查询来回答。查询是

SELECT
*
 FROM
 (
    SELECT
 *
    FROM meterdata  
 ) AS P
PIVOT
(
  sum (power ) FOR meterno IN (89, 90)
) AS pv1 
PIVOT
(
  sum (frequency ) FOR meterno IN (89, 90)
) AS pv2 

GO

【问题讨论】:

    标签: sql-server sql-server-2008 pivot


    【解决方案1】:

    动态 SQL 将为您提供帮助(我使用了 ##MeterData 和 tempdb,您必须使用您的实际表和数据库名称)。将使用源表中的任意数量的列。几个cmets:

    • 您需要将CAST 或CONVERT 的所有列归为一种类型(我在@p 变量中使用了nvarchar(10));
    • 我排除列meterno、date、timeblock,因为您的数据集中没有用作参数;
    • 您可以在执行前PRINT @sql查看已形成执行的内容。

    这里是查询:

    DECLARE @p nvarchar(max), @c nvarchar(max), @s nvarchar(max), @sql nvarchar(max)
    
    --That will get you this:
    --,CAST([power] as nvarchar(10)) [power],CAST([frequency] as nvarchar(10)) [frequency]
    SELECT @p = (
    SELECT ',CAST(' + QUOTENAME(COLUMN_NAME) + ' as nvarchar(10)) '+ QUOTENAME(COLUMN_NAME)
    FROM tempdb.INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = N'##MeterData' AND COLUMN_NAME NOT IN ('meterno','date','timeblock')
    FOR XML PATH('')
    )
    --[power],[frequency]
    SELECT @c = STUFF((
    SELECT ',' + QUOTENAME(COLUMN_NAME) 
    FROM tempdb.INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = N'##MeterData' AND COLUMN_NAME NOT IN ('meterno','date','timeblock')
    FOR XML PATH('')),1,1,'')
    --[frequency89],[frequency90],[power89],[power90]
    SELECT @s = STUFF((
    SELECT DISTINCT ','+QUOTENAME(COLUMN_NAME + CAST(meterno as nvarchar(10)))
    FROM ##MeterData m
    CROSS JOIN (
        SELECT COLUMN_NAME
        FROM tempdb.INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = N'##MeterData' AND COLUMN_NAME NOT IN ('meterno','date','timeblock')
    ) as p 
    FOR XML PATH('')),1,1,'')
    --Put it all in dynamic query
    SELECT @sql = '
    SELECT *
    FROM (
        SELECT  [date],
                timeblock,
                params + CAST(meterno as nvarchar(10)) as params,
                [values]
        FROM (
            SELECT  meterno, 
                    [date], 
                    timeblock'
                    +@p+
                    '
            FROM ##MeterData
            ) as p
        UNPIVOT (
            [values] FOR params IN ('+@c+')
        ) as unpvt
    ) as p2
    PIVOT (
        MAX([Values]) FOR params IN ('+@s+')
    ) as pvt'
    --And execute
    EXEC sp_executesql @sql
    

    输出:

    date        timeblock   frequency89 frequency90 power89 power90
    2016-04-01  1           50.02       50.02       500     200
    2016-04-01  2           49.99       49.89       100     300
    

    【讨论】:

    • 感谢@gofr1,为您提供出色的答案。从过去两天开始,我一直在尝试完成此任务,而您在短短几分钟内就解决了。
    【解决方案2】:

    这是一个您可以尝试的不使用 SQL Server PIVOT 操作的数据透视查询:

    SELECT date, timeblock
        SUM(CASE WHEN meterno=89 THEN power     ELSE 0 END) AS meterno-89_power,
        SUM(CASE WHEN meterno=90 THEN power     ELSE 0 END) AS meterno-90_power,
        SUM(CASE WHEN meterno=89 THEN frequency ELSE 0 END) AS meterno-89_frequency,
        SUM(CASE WHEN meterno=90 THEN frequency ELSE 0 END) AS meterno-89_frequency
    FROM MeterData
    GROUP BY date, timeblock
    

    【讨论】:

    • 感谢蒂姆的早日回复。但我之前没有提到meterno 列是可变的,即它可以有任何值,例如 89,90,91,95 .....
    • 如果meterno 只有一组固定的值,那么只需通过添加额外的CASE 语句来相应地修改我的查询。如果列数较大或多变,则需要使用动态 SQL 来处理。
    • 它不大,但可变。在这种情况下我该如何使用动态sql?即我想要现成的查询!
    • 你可以尝试在Stack Overflow上搜索这个解决方案,之前已经回答过很多次了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-26
    • 2021-11-19
    • 2023-04-08
    相关资源
    最近更新 更多