如何在SQL Server中进行透视后对列的平均值进行分组

时间:2016-10-24 20:50:25

标签: sql sql-server stored-procedures pivot pivot-table

我有以下几行SQL代码,它们是存储过程的一部分:

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME([vw_Imported_Files].RF_FileName) 
        FROM [dbo].[vw_Imported_Files] with(nolock)
        WHERE [vw_Imported_Files].RF_GUID_ID = @sGUID 
AND [vw_Imported_Files].RF_IsEnabled = 1
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

SET @query2 = 'SELECT  ROUND(AVG(CAST(RD_Axis AS FLOAT)),3) AS RD_Axis
,' + @cols + ' FROM
(SELECT ROW_NUMBER() OVER (PARTITION BY DenseRank ORDER BY (SELECT NULL)) 
AS RowNumber, rd.* FROM 
   (SELECT DENSE_RANK() OVER (ORDER BY rd.RD_RF_ID) AS DenseRank
    ,rd.RD_Axis AS RD_Axis
    ,rd.DN_Values AS DN_Values
    ,rd.RF_FileName AS RF_FileName
  FROM #TEMP rd
  WHERE rd.RD_GUID_ID = ' + @sGUID + '
  AND rd.RD_IsEnabled = 1

 ) rd  
    ) rn 
    pivot 
        (
            max(DN_Values)
            for RF_FileName in (' + @cols + ')
        ) p
GROUP BY RD_Axis, ' + @cols + ' '

execute (@query2)

实际上,此查询(@ query2)的结果如下表所示。

---------------------------------------------------------------
|   0       |   NULL                | NULL              | 0,996573652935408|
|   0       |   NULL                | 1,00053003751428  | NULL             |
|   0       |   0,999843071844672   | NULL              | NULL             |
|   0,052   |   NULL                | NULL              | 0,992999630825293|
|   0,052   |   1,02368347072563    | NULL              | NULL             |
|   0,053   |   NULL                | 0,992674427713489 | NULL             |
|   0,104   |   NULL                | NULL              | 0,998690236570867|
|   0,104   |   NULL                | 0,996645964692132 | NULL             |
|   0,105   |   0,989815140503533   | NULL              | NULL             |
----------------------------------------------------------------------------

我想要做的是通过对具有相同DenseRank值的RD_Axis值的NULL进行分组来清除所有Average值。在当前实例中,DenseRank每3行增加一次。所以,我想要的结果必须如下表所示。

----------------------------------------------------------------------------
| 0        |  0,999843071844672    |  1,00053003751428  | 0,996573652935408|
| 0,052    |  1,02368347072563     |  0,992674427713489 | 0,992999630825293|
| 0,104    |  0,989815140503533    |  0,996645964692132 | 0,998690236570867|
----------------------------------------------------------------------------

我希望明白我的询问。你能帮我弄清楚如何转换上面的SQL代码,以便我得到理想的结果吗?

2 个答案:

答案 0 :(得分:1)

您可能需要创建一个新的列变量来获取外部选择的MAX(dynamicColumn)值。这样就可以在最后删除GROUP BY。

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME([vw_Imported_Files].RF_FileName) 
        FROM [dbo].[vw_Imported_Files] with(nolock)
        WHERE [vw_Imported_Files].RF_GUID_ID = @sGUID 
AND [vw_Imported_Files].RF_IsEnabled = 1
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

SET @maxCols = STUFF((SELECT distinct ', MAX(' + QUOTENAME([vw_Imported_Files].RF_FileName) + ') AS ' + QUOTENAME([vw_Imported_Files].RF_FileName)
        FROM [dbo].[vw_Imported_Files] with(nolock)
        WHERE [vw_Imported_Files].RF_GUID_ID = @sGUID 
AND [vw_Imported_Files].RF_IsEnabled = 1
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

SET @query2 = '
    SELECT  ROUND(AVG(CAST(RD_Axis AS FLOAT)),3) AS RD_Axis
    ,' + @maxCols + ' 
    FROM
        (SELECT ROW_NUMBER() OVER (PARTITION BY DenseRank ORDER BY (SELECT NULL)) 
                AS RowNumber, rd.* 
         FROM (SELECT DENSE_RANK() OVER (ORDER BY rd.RD_RF_ID) AS DenseRank
                    ,rd.RD_Axis AS RD_Axis
                    ,rd.DN_Values AS DN_Values
                    ,rd.RF_FileName AS RF_FileName
               FROM #TEMP rd
               WHERE rd.RD_GUID_ID = ' + @sGUID + ' AND rd.RD_IsEnabled = 1

            ) rd  
        ) rn 
    pivot 
        (
            max(DN_Values)
            for RF_FileName in (' + @cols + ')
        ) p 
    GROUP BY DenseRank'

execute (@query2)

这可以在不使用PIVOT的情况下完成,并且通过使用带有CASE表达式的聚合来更加清晰

答案 1 :(得分:0)

其实我用以下代码得到了我正在寻找的结果。

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME([vw_Imported_Files].RF_FileName) 
        FROM [dbo].[vw_Imported_Files] with(nolock)
        WHERE [vw_Imported_Files].RF_GUID_ID = @sGUID and [vw_Imported_Files].RF_IsEnabled = 1
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

SET @maxCols = STUFF((SELECT distinct ', MAX(' + QUOTENAME([vw_Imported_Files].RF_FileName) + ') AS ' + QUOTENAME([vw_Imported_Files].RF_FileName)
    FROM [dbo].[vw_Imported_Files] with(nolock)
    WHERE [vw_Imported_Files].RF_GUID_ID = @sGUID AND [vw_Imported_Files].RF_IsEnabled = 1
    FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)') 
,1,1,'')

SET @query2 = '
SELECT  ' + @maxCols + ' 
FROM
    (SELECT ROW_NUMBER() OVER (PARTITION BY DenseRank ORDER BY (SELECT NULL)) 
            AS RowNumber, rd.* 
     FROM (SELECT DENSE_RANK() OVER (ORDER BY rd.RD_RF_ID) AS DenseRank
                ,rd.RD_Axis AS RD_Axis
                ,rd.DN_Values AS DN_Values
                ,rd.RF_FileName AS RF_FileName
           FROM #TEMP rd
           WHERE rd.RD_GUID_ID = ' + @sGUID + ' AND rd.RD_IsEnabled = 1

        ) rd  
    ) rn 
pivot 
    (
        max(DN_Values)
        for RF_FileName in (' + @cols + ')
    ) p 
GROUP BY RowNumber ORDER BY RowNumber'

execute (@query2)

首先我生成了我想要的结果(@ query2),然后我得到了另一个查询的RD_Axis值的平均值(均由Rownumber asc排序)。然后我用UNION ALL语句将它们链接起来。顺便说一句,感谢我对我的问题的全新观点,因为我已经被困了几个小时。