Sql server SQL Server通过使用单个取消PIVOT,根据条件组合两行来取消PIVOT表
我有一个大查询,它给出了如下的表结果:Sql server SQL Server通过使用单个取消PIVOT,根据条件组合两行来取消PIVOT表,sql-server,row,conditional-statements,rows,unpivot,Sql Server,Row,Conditional Statements,Rows,Unpivot,我有一个大查询,它给出了如下的表结果: [Date] [Type] TC1 TC2 TC3 .......................................... '2014-01-01' T 11 22 33 '2014-01-01' C 44 55 66 '2014-01-02' T 111 222 333 '2014-01-02' C 4
[Date] [Type] TC1 TC2 TC3
..........................................
'2014-01-01' T 11 22 33
'2014-01-01' C 44 55 66
'2014-01-02' T 111 222 333
'2014-01-02' C 444 555 666
'2014-01-03' T 1111 2222 3333
'2014-01-04' C 4444 5555 6666
[Date] Cntr TValue CValue
............................................
'2014-01-01' TC1 11 44
'2014-01-01' TC2 22 55
'2014-01-01' TC3 33 66
'2014-01-02' TC1 111 444
'2014-01-02' TC2 222 555
'2014-01-02' TC3 333 666
'2014-01-03' TC1 1111 4444
'2014-01-03' TC2 2222 5555
'2014-01-03' TC3 3333 6666
我想让它看起来像这样:
[Date] [Type] TC1 TC2 TC3
..........................................
'2014-01-01' T 11 22 33
'2014-01-01' C 44 55 66
'2014-01-02' T 111 222 333
'2014-01-02' C 444 555 666
'2014-01-03' T 1111 2222 3333
'2014-01-04' C 4444 5555 6666
[Date] Cntr TValue CValue
............................................
'2014-01-01' TC1 11 44
'2014-01-01' TC2 22 55
'2014-01-01' TC3 33 66
'2014-01-02' TC1 111 444
'2014-01-02' TC2 222 555
'2014-01-02' TC3 333 666
'2014-01-03' TC1 1111 4444
'2014-01-03' TC2 2222 5555
'2014-01-03' TC3 3333 6666
我成功地做到了这一点,取消了两次激励,然后加入结果。
我提出的问题如下:
SELECT A.[Date],A.Cntr,A.TValue,B.CValue
FROM
(
SELECT [Date],Cntr,TValue
FROM TB
UNPIVOT
(
TValue
FOR Cntr IN (TC1,TC2,TC3)
) u
WHERE [Type] = 'T' AND u.[Type] = 'T'
) A
JOIN
(
SELECT [Date],Cntr,CValue
FROM TB
UNPIVOT
(
CValue
FOR Cntr IN (TC1,TC2,TC3)
) u
WHERE [Type] = 'C' AND u.[Type] = 'C'
) B
ON B.[Date] = A.[Date] AND A.[Cntr] = B.[Cntr]
我的问题是TB表来自一个大而耗时的查询,而且在我的存储过程中,它将被调用数千次,因此我不想在临时表中插入它的许多行,从而浪费宝贵的时间
有没有一种方法可以通过使用一个unpivot或使用更好的方法来解决此问题?
此外,它必须在SQLServer>=2005上运行
SqlFiddle
谢谢大家! 由于(Date/Type
)在TB
中被约束为唯一的,因此您可以UNPIVOT
,然后PIVOT
避免联接,MAX(Value)是一个任意聚合,因为无论如何只能有一个值
SELECT pvt.Date,
pvt.Cntr,
TValue = pvt.T,
CValue = pvt.C
FROM TB
UNPIVOT (Value FOR Cntr IN (TC1, TC2, TC3)) AS upvt
PIVOT (MAX(Value) FOR [Type] IN (C, T)) AS pvt;
这将导致读取次数减少一半(正如您可能预期的那样)。IO统计数据显示:
UNPIVOT/PIVOT
表“TB”。扫描计数1,逻辑读取1,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0
UNPIVOT/UNPIVOT/JOIN
表“工作台”。扫描计数0,逻辑读取0,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0
表“TB”。扫描计数2,逻辑读取2,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0
以及一个更简单的执行计划(顶部为UNPIVOT/PIVOT):
由于(Date/Type
)在TB
中被约束为唯一的,因此您可以UNPIVOT
,然后PIVOT
避免联接,MAX(Value)是任意聚合,因为无论如何只能有一个值
SELECT pvt.Date,
pvt.Cntr,
TValue = pvt.T,
CValue = pvt.C
FROM TB
UNPIVOT (Value FOR Cntr IN (TC1, TC2, TC3)) AS upvt
PIVOT (MAX(Value) FOR [Type] IN (C, T)) AS pvt;
这将导致读取次数减少一半(正如您可能预期的那样)。IO统计数据显示:
UNPIVOT/PIVOT
表“TB”。扫描计数1,逻辑读取1,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0
UNPIVOT/UNPIVOT/JOIN
表“工作台”。扫描计数0,逻辑读取0,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0
表“TB”。扫描计数2,逻辑读取2,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0
以及一个更简单的执行计划(顶部为UNPIVOT/PIVOT):
一种方法是使用交叉应用和条件聚合:
select [date], [cntr],
max(case when [type] = 'T' then val end) as TValue,
max(case when [type] = 'C' then val end) as CValue
from (<your query here>) t cross apply
(values ([date], [type], 'tc1', tc1),
([date], [type], 'tc2', tc2),
([date], [type], 'tc3', tc3)
) vals([date], [type], cntr, val)
group by [date], [cntr];
一种方法是使用交叉应用和条件聚合:
select [date], [cntr],
max(case when [type] = 'T' then val end) as TValue,
max(case when [type] = 'C' then val end) as CValue
from (<your query here>) t cross apply
(values ([date], [type], 'tc1', tc1),
([date], [type], 'tc2', tc2),
([date], [type], 'tc3', tc3)
) vals([date], [type], cntr, val)
group by [date], [cntr];
日期/类型在TB中是否被限制为唯一?如果不是,即在一个日期有两条类型为
T
的记录和两条类型为“C”的记录,那么您如何在不创建笛卡尔积的情况下匹配每一条T和C,或者笛卡尔积是所需的结果?很抱歉理解错误!是的,日期和类型将始终是唯一的。日期/类型在TB中是否被限制为唯一?如果不是,即在一个日期有两条类型为T
的记录和两条类型为“C”的记录,那么您如何在不创建笛卡尔积的情况下匹配每一条T和C,或者笛卡尔积是所需的结果?很抱歉理解错误!是的,日期和类型总是唯一的谢谢你的快速回答。我不会想到这个解决方案。我将在我的SP中使用它,因为它的性能更好!谢谢你的快速回答。我不会想到这个解决方案。我将在我的SP中使用它,因为它的性能更好!我曾想过交叉申请,但泰国工会全体成员都支持我。不过我会尝试一下:)我曾想过交叉申请,但泰国工会全体支持我。不过我会试试看:)