使用UNPIVOT和SELECT MAX()将行数据中的SELECT MAX()值转换为列数据

时间:2014-10-24 09:11:04

标签: sql sql-server pivot max

我有一个名为金额的表,如下所示:

// structure 1
+-----+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT | SUN |
+-----+-----+-----+-----+-----+-----+-----+
| 1   | 6   | 3   | 1   | 1   | 3   | 0   |
+-----+-----+-----+-----+-----+-----+-----+

我需要从上面的行中获取MAX()值(表中只有一行)。

我怎样才能PIVOT表格,使其如下所示:

// structure 2
+-----+-----+
| DAY | AMT |
+-----+-----+
| MON | 1   |
+-----+-----+
| TUE | 6   |
+-----+-----+
| WED | 3   |
+-----+-----+
| THU | 1   |
+-----+-----+
| FRI | 1   |
+-----+-----+
| SAT | 3   |
+-----+-----+
| SUN | 0   |
+-----+-----+

...然后选择MAX()列的AMT值:

SELECT MAX(AMT)
FROM (
    SELECT * FROM amounts
) AS amts
PIVOT (
    AMT FOR * IN ... // got stuck here, pivots are confusing
) AS highest_amt

有更有效的方法吗?

3 个答案:

答案 0 :(得分:3)

您无需取消结果。在您的情况下,结果来自报告视图,这可能会导致执行计划效率低下。

您可以使用VALUES构造函数从视图的列创建值表,然后获取最大值,如下所示:

select MAX(dayvalues.v)
from 
amounts          
CROSS APPLY (VALUES  (amounts.MON),(amounts.TUE),(amounts.WED),(amounts.THU),
                     (amounts.FRI),(amounts.SAT),(amounts.SUN)
            ) dayvalues(v)

VALUES将根据amounts中的值创建一个表格,然后MAX将选择最大值。 CROSS APPLY在左侧的每一行上应用右侧的表值函数(VALUES)。

这意味着视图只执行一次

答案 1 :(得分:1)

实际上unpivot不是pivot !!

数据透视 - 行到列

UnPivot - 列到行

试试这个..

CREATE TABLE #temp
  (
     MON INT,
     TUE INT,
     WED INT,
     THU INT,
     FRI INT,
     SAT INT,
     SUN INT
  )

INSERT INTO #temp
VALUES     (1,2,3,4,5,6,7)

SELECT *
FROM   #temp

;WITH cte
     AS (SELECT value,
                col,
                Row_number()
                  OVER(
                    ORDER BY value DESC) rn
         FROM   #temp
                UNPIVOT ( value
                        FOR col IN (MON,
                                    TUE,
                                    WED,
                                    THU,
                                    FRI,
                                    SAT,
                                    SUN ) ) unpiv)
SELECT value,
       COL AS AMT
FROM   cte
WHERE  rn = 1 

答案 2 :(得分:1)

我能想象的有效方法是分别对每一列进行最大化,然后使用union来获得最大值。

with t(v) as(
    select max(MON) from amounts 
    union
    select max(TUE) from amounts 
    union ... 
    select max(SUN) from amounts 
)
select max(v)
from t

可以这样改进:

with 
    m   as(
    select 
        max(MON) as MON,
        ...
        max(SUN) as SUN
    from amounts 
    )
   ,t(v) as(
    select MON from m
    union
    select TUE from m
    union ... 
    select SUN from m
)
select max(v)
from t

<强>更新

根据@ PanagiotisKanavos的评论,我意识到SQL SERVER将运行相同的视图7次。但是在其他DBMS中,例如ORACLE只会先进行一次表扫描来聚合7列,这样可以真正节省时间。

幸运的是,values子句可以在SQL SERVER中完成,在聚合之后加入7列比聚合之前的交叉连接更有效。您可以使用this SQL FIDDLE DEMO比较查询计划。

with m as(
    select 
        max(MON) as MON,
        max(TUE) as TUE,
        ...
        max(SUN) as SUN
    from amounts 
    )
select 
    (select max(v) 
         from 
             (values
                 (m.MON)
                ,(m.TUE)
                ...
                ,(m.SUN)
             )t(v)
    )
from m;