可以在不重复的情况下编写使用相同过滤表进行逆透视和连接的查询吗?

问题描述 投票:0回答:1

考虑以下查询:

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
)

这显然是高度重复的。有两点很突出

  1. table1
    被给予相同的过滤器三次。我将其替换为 CTE,但选择列表在第一次使用其余部分之间有所不同,因此根据索引情况,这可能会产生很大的性能影响。
  2. union all
    看起来都非常相似。事实上,我也可以将
    unpivot
    写为一组三个
    union all
    ,这表明当前在查询中的两个
    union all
    应该以某种方式合并到
    unpivot
    中。

T-SQL中有什么可以解决这两个问题吗?

sql sql-server tsql unpivot union-all
1个回答
1
投票

不完全是这样,但是您可以通过将

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
© www.soinside.com 2019 - 2024. All rights reserved.