Sql 使用UNPIVOT从转换为列数据的行数据中选择MAX()值,然后选择MAX()
我有一个名为amounts的表,如下所示:Sql 使用UNPIVOT从转换为列数据的行数据中选择MAX()值,然后选择MAX(),sql,sql-server,pivot,max,Sql,Sql Server,Pivot,Max,我有一个名为amounts的表,如下所示: // structure 1 +-----+-----+-----+-----+-----+-----+-----+ | MON | TUE | WED | THU | FRI | SAT | SUN | +-----+-----+-----+-----+-----+-----+-----+ | 1 | 6 | 3 | 1 | 1 | 3 | 0 | +-----+-----+-----+-----+-----+-----+
// structure 1
+-----+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT | SUN |
+-----+-----+-----+-----+-----+-----+-----+
| 1 | 6 | 3 | 1 | 1 | 3 | 0 |
+-----+-----+-----+-----+-----+-----+-----+
// structure 2
+-----+-----+
| DAY | AMT |
+-----+-----+
| MON | 1 |
+-----+-----+
| TUE | 6 |
+-----+-----+
| WED | 3 |
+-----+-----+
| THU | 1 |
+-----+-----+
| FRI | 1 |
+-----+-----+
| SAT | 3 |
+-----+-----+
| SUN | 0 |
+-----+-----+
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
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)
我需要从上面的行中获取MAX()
值(该表只有一行)
我怎样才能将表透视成这样:
// structure 1
+-----+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT | SUN |
+-----+-----+-----+-----+-----+-----+-----+
| 1 | 6 | 3 | 1 | 1 | 3 | 0 |
+-----+-----+-----+-----+-----+-----+-----+
// structure 2
+-----+-----+
| DAY | AMT |
+-----+-----+
| MON | 1 |
+-----+-----+
| TUE | 6 |
+-----+-----+
| WED | 3 |
+-----+-----+
| THU | 1 |
+-----+-----+
| FRI | 1 |
+-----+-----+
| SAT | 3 |
+-----+-----+
| SUN | 0 |
+-----+-----+
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
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)
。。。然后选择AMT
列的MAX()
值:
SELECT MAX(AMT)
FROM (
SELECT * FROM amounts
) AS amts
PIVOT (
AMT FOR * IN ... // got stuck here, pivots are confusing
) AS highest_amt
有更有效的方法吗?实际上是
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
我能想象的最有效的方法是分别最大化每一列,然后并集以获得最大值
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
可以这样改进:
// structure 1
+-----+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT | SUN |
+-----+-----+-----+-----+-----+-----+-----+
| 1 | 6 | 3 | 1 | 1 | 3 | 0 |
+-----+-----+-----+-----+-----+-----+-----+
// structure 2
+-----+-----+
| DAY | AMT |
+-----+-----+
| MON | 1 |
+-----+-----+
| TUE | 6 |
+-----+-----+
| WED | 3 |
+-----+-----+
| THU | 1 |
+-----+-----+
| FRI | 1 |
+-----+-----+
| SAT | 3 |
+-----+-----+
| SUN | 0 |
+-----+-----+
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
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)
更新
根据@PanagiotisKanavos的评论,我意识到SQL SERVER将运行同一视图7次。但在其他数据库管理系统中,如ORACLE,只需先进行一次表扫描就可以聚合7列,这确实可以为这种情况节省时间
幸运的是,在SQL SERVER中,values
子句可以做到这一点,聚合后连接7列比聚合前交叉连接更有效。您可以使用比较查询计划
您不需要取消打印结果。在您的情况下,如果结果来自报告视图,这可能会导致执行计划效率低下 您可以使用
VALUES
构造函数从视图的列中创建一个值表,然后获得如下所示的最大值:
// structure 1
+-----+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT | SUN |
+-----+-----+-----+-----+-----+-----+-----+
| 1 | 6 | 3 | 1 | 1 | 3 | 0 |
+-----+-----+-----+-----+-----+-----+-----+
// structure 2
+-----+-----+
| DAY | AMT |
+-----+-----+
| MON | 1 |
+-----+-----+
| TUE | 6 |
+-----+-----+
| WED | 3 |
+-----+-----+
| THU | 1 |
+-----+-----+
| FRI | 1 |
+-----+-----+
| SAT | 3 |
+-----+-----+
| SUN | 0 |
+-----+-----+
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
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
将选择最大值<代码>交叉应用将其右侧的表值函数(值)应用于左侧的每一行
这意味着该视图只执行一次在google中有大量答案!!如果您有超过一行,您希望得到什么?您要查找的操作员称为
UNPIVOT
btw@PanagiotisKanavos,amounts表中只有一行,它实际上是为报告而创建的视图purposes@proPhet这意味着有大量数据聚合到一行。在这种情况下,取消激励可能会导致执行计划效率低下。数据来自报告视图。这会很糟糕performance@PanagiotisKanavos第二个sql呢?最糟糕的可能是,您仍然运行同一个视图7次(每个联合一次)。添加聚合充其量也无济于事,因为视图只返回一行already@PanagiotisKanavos很抱歉,我没有在SQLServer中检查查询计划,但它在其他DBMS(如ORACLE和DB2)中确实有效。我找到了另一个解决方案并更新了我的答案,我认为这种方式确实更好。你确定其他RDBMS吗?它们中的查询优化器都必须决定如何处理7个必须联合的不同聚合操作。他们中会有人将其转换为单个聚合吗?这并不是说SQL Server很笨(实际上它有一个更好的优化器),而是在一个视图上强制执行多个聚合,而不检查结果的执行工厂。数据来自报告视图。取消激活它可能会导致性能下降,如果它干扰视图的执行计划。这是一种优雅、高效的方法,适用于任意数量的行,不像这里的其他答案。