我有一个名为金额的表,如下所示:
// 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
有更有效的方法吗?
答案 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;