Consider the following query:
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
)
this is obviously highly repetitive. Two things stand out
table1
is given the same filter thrice. I'd replace it with a CTE, but the select list is different between the first use the rest, so this could have a big performance hit depending on the indexing situation.union all
s all look very similar. The fact that I could have also written the unpivot
as a set of three union all
s suggests that the two union all
s that are currently within the query should somehow be merged in to the unpivot
.Is there anything in T-SQL that can tackle these two problems?
Not entirely, however you can avoid looking up table1
multiple times by putting the UNION ALL
in an APPLY
.
Use a (VALUES
constructor instead of UNPIVOT
, it is far more flexible.
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;
You could also replace the VALUES
with a few UNION ALL
, bu it's more verbose.
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