【问题标题】:Using a recursive CTE in a view在视图中使用递归 CTE
【发布时间】:2016-10-19 13:59:28
【问题描述】:

拥有一个典型的父/子层次结构表,使用Common Table Expression 查询它是很常见的事情:

 with CTE  as (
    select Id, ProviderId, ConsumerId
    from T1
    where ProviderId in (2, 3, 9)

    union all
    select T1.Id, T1.ProviderId, T1.ConsumerId
    from T1  
    join CTE on C.ProviderId = CTE.ConsumerId 
)
select * from CTE

是否可以根据这个查询创建一个视图,以便可以做到:

select * from MagicView where ProviderId in (2,3,9)

换句话说,我们能否以某种方式从 CTE 的锚点部分提取参数来创建通用视图?

【问题讨论】:

  • 我不明白你想做什么。问题是什么?将 cte 放在视图中? dba.stackexchange.com/questions/7239/…
  • @JuanCarlosOropeza 听起来他在问递归 cte 是否可以在视图定义中。您的链接说 cte 可以。我不明白为什么递归 cte 不起作用,但我从未尝试过。 UserControl 只是试一试,它只需要多几行代码 CREATE VIEW AS,你的第一个块几乎就是你所需要的。
  • @UserControl 这篇文章说你可以,但你可能需要在视图定义本身中不使用 MAXRECURSION benchmarkitconsulting.com/colin-stasiuk/2010/04/12/…
  • 您想从外部将参数传递给 CTE?使用带有 TVP 参数而不是视图的内联表值函数怎么样?
  • @JamesZ 很好地抓住了 cte 中的参数没有看到我同意带有表值参数的表值函数似乎也适合我。除非您想要视图中的整个递归表,并且您有一个大型数据集并且需要性能,否则我可能会尝试索引视图。

标签: sql sql-server recursion view common-table-expression


【解决方案1】:

表值路由的一种方法

CREATE FUNCTION [dbo].[MVParam_tvf](@ParameterString nvarchar(4000), @Delimiter char(1)= ',')
RETURNS @VALUES TABLE (Param nvarchar(4000))AS

Figure out your code preference to spilt delimited string to table

END

CREATE FUNCTION dbo.MagicView_tvf
(   
    @ParameterString  NVARCHAR(4000)
    ,@Delimiter CHAR(1)
)
RETURNS TABLE 
AS
RETURN 
(
    with CTE  as (
       select Id, ProviderId, ConsumerId
       from
          T1 t
          INNER JOIN MVParam_tvf (@ParameterString, @Delimiter) p
          ON CAST(t.ProviderId AS VARCHAR(10)) = p.OutPutColumn

       union all
       select T1.Id, T1.ProviderId, T1.ConsumerId
       from T1  
       join CTE on C.ProviderId = CTE.ConsumerId 
    )
    select * from CTE
)
GO

SELECT * FROM dbo.MagicView_tvf ('2,3,9')

如果您想查看视图路线,请在 cte 的锚点部分创建没有 where 行的视图,然后在调用它时在该查询上编写您的 where 语句。

【讨论】:

    【解决方案2】:

    创建一个 TVF:

    CREATE FUNCTION my_function (
        @ProviderId int
    )
    RETURNS @ProviderTable TABLE 
    (
        Id int NULL, 
        ProviderId int NULL,
        ConsumerId int NULL
    )
    AS 
    BEGIN
        WITH cte AS (
            SELECT  Id, 
                    ProviderId, 
                    ConsumerId
            FROM T1
            WHERE ProviderId in (@ProviderId)
            UNION ALL
            SELECT  t.Id, 
                    t.ProviderId, 
                    t.ConsumerId
            FROM T1 t 
            INNER JOIN cte c 
                ON t.ProviderId = c.ConsumerId 
        )
    
        INSERT INTO @ProviderTable
        SELECT * FROM cte;
    
        RETURN;
    END;
    

    比创建视图:

    CREATE VIEW my_view
    AS 
    SELECT m.*
    FROM Providers p
    CROSS APPLY my_function (p.ProviderId) m
    

    之后,您可以从视图中选择您需要的任何内容:

    SELECT * 
    FROM my_view 
    WHERE ProviderId in (2,3,9)
    OPTION (MAXRECURSION 0)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多