Sql server 透视sql server表

Sql server 透视sql server表,sql-server,sql-server-2008,pivot,Sql Server,Sql Server 2008,Pivot,如何使用SQL查询将SQL Server表meterdata转换为Result\u表 MeterData表存储功率和频率,并具有主键(meterno,date,timeblock),meterno列具有可变的值编号 MeterData表格: meterno date timeblock power frequency -------------------------------------------------- 89 1-Apr-16 1

如何使用SQL查询将SQL Server表
meterdata
转换为
Result\u表

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     
结果表

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)。我正在尝试以下查询,但没有得到结果。是否有人可以编辑查询结果,以便输出如上所示的结果表。最好使用pivot query进行回答。问题是

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

以下是一个pivot查询,您可以尝试它不使用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

以下是一个pivot查询,您可以尝试它不使用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
动态SQL将帮助您(我使用了
##MeterData
tempdb
您必须使用实际的表和数据库名称)。将处理源表中任意数量的列。几点意见:

  • 您需要将所有列转换为一种类型(我在
    @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
动态SQL将帮助您(我使用了
##MeterData
tempdb
您必须使用实际的表和数据库名称)。将处理源表中任意数量的列。几点意见:

  • 您需要将所有列转换为一种类型(我在
    @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

谢谢蒂姆早日回复。但我之前没有提到meterno列是可变的,即它可以没有任何值,如89、90、91、95……如果
meterno
只有一组固定的值,那么只需通过添加额外的
CASE
语句来相应地修改我的查询。如果列数很大或可变,则需要使用动态SQL来处理。它不是很大,而是可变的。在这种情况下,如何使用动态SQL?i、 我想要现成的查询!您可以尝试搜索此解决方案的堆栈溢出,它已被回答了很多次。感谢Tim的早期答复。但我之前没有提到meterno列是可变的,即它可以没有任何值,如89、90、91、95……如果
meterno
只有一组固定的值,那么只需通过添加额外的
CASE
语句来相应地修改我的查询。如果列数很大或可变,则需要使用动态SQL来处理。它不是很大,而是可变的。在这种情况下,如何使用动态SQL?i、 我想要现成的查询!您可以尝试搜索此解决方案的堆栈溢出,它以前已被回答过多次。感谢@gofr1给出的精彩回答。在过去的两天里,我一直在努力完成这个任务,而你在几分钟内就解决了。谢谢@gofr1,给了我一个精彩的回答。在过去的两天里,我一直在努力完成这个任务,而你在几分钟内就解决了这个问题。