考虑以下查询:
create function unpivoter(@TableID int)
returns table
as
return
(
select a, b
from
(
select foo1, foo2, foo3, foo4
from table1
where table1.id = @TableID
) tab_in
unpivot
(a for b in (foo1, foo2, foo3, foo4)) tab_out
union all
select t3.a, t3.b,
from table1 t1
join t2 on t1.id = t2.id
join t3 on t3.id = t2.id
where t1.id = @TableID
union all
select t4.a, t4.b,
from table1 t1
join t4 on t4.id = t4.id
where t1.id = @TableID
)
这显然是高度重复的。有两点很突出
table1
被给予相同的过滤器三次。我将其替换为 CTE,但选择列表在第一次使用其余部分之间有所不同,因此根据索引情况,这可能会产生很大的性能影响。union all
看起来都非常相似。事实上,我也可以将 unpivot
写为一组三个 union all
,这表明当前在查询中的两个 union all
应该以某种方式合并到 unpivot
中。T-SQL中有什么可以解决这两个问题吗?
不完全是这样,但是您可以通过将
table1
放入 UNION ALL
中来避免多次查找 APPLY
。
使用
(VALUES
构造函数而不是 UNPIVOT
,它更加灵活。
CREATE OR ALTER FUNCTION dbo.unpivoter (@TableID int)
RETURNS TABLE
AS RETURN
SELECT
u.a,
u.b
FROM table1 t1
CROSS APPLY (
SELECT
tab_out.a,
tab_out.b
FROM (VALUES
('foo1', t1.foo1),
('foo2', t1.foo2),
('foo3', t1.foo3),
('foo4', t1.foo4)
) tab_out(a, b)
UNION ALL
SELECT
t3.a,
t3.b,
FROM t2
JOIN t3 ON t3.id = t2.id
WHERE t2.id = t1.id
UNION ALL
SELECT
t4.a,
t4.b,
FROM t4
WHERE t4.id = t1.id
) u
WHERE t1.id = @TableID;
您也可以将
VALUES
替换为几个 UNION ALL
,但这样会更冗长。
CROSS APPLY (
SELECT
'foo1' AS a,
t1.foo1 AS b
UNION ALL
SELECT
'foo2' AS a,
t1.foo2 AS b
UNION ALL
SELECT
'foo3' AS a,
t1.foo3 AS b
UNION ALL
SELECT
'foo4' AS a,
t1.foo4 AS b
UNION ALL