sql递归cte在视图中不能正常工作

Posted

技术标签:

【中文标题】sql递归cte在视图中不能正常工作【英文标题】:sql recursive cte in view not work fine 【发布时间】:2016-06-17 11:18:51 【问题描述】:

我做了一个 CTE 查询,它可以在存储过程中正常工作,并且当我在查询编辑器中执行时(使用 where 语句)

但是当我尝试创建与 View 相同的视图时(没有 where 语句)。 并使用 where 语句执行此操作,我得到的数据不是递归的。 我没有看到错误。

这是 SP 中的查询和查询编辑器,可以正常工作。 (SP中的Guid作为参数)

WITH recursiveTable(ParentApplicationRoleId, ChildApplicationRoleId)
AS
(
    SELECT ParentApplicationRoleId, ChildApplicationRoleId
        FROM ApplicationRoleParentChild
        WHERE ParentApplicationRoleId = '69BCC94B-2884-4270-B39E-A09669C1D658'
    UNION ALL
    SELECT ApplicationRoleParentChild.ParentApplicationRoleId, ApplicationRoleParentChild.ChildApplicationRoleId
        FROM ApplicationRoleParentChild
        INNER JOIN recursiveTable ON ApplicationRoleParentChild.ParentApplicationRoleId = recursiveTable.ChildApplicationRoleId   
)
/* Get all Childelements (from recursive Table) and add the ParentRoleId to this List */
SELECT ApplicationRole.Name AS RoleName
    FROM recursiveTable
    INNER JOIN ApplicationRole ON ApplicationRole.ApplicationRoleId = recursiveTable.ChildApplicationRoleId 
    UNION
    SELECT Name AS RoleName FROM ApplicationRole WHERE ApplicationRoleId = '69BCC94B-2884-4270-B39E-A09669C1D658'
OPTION(MAXRECURSION 32767)

结果我得到Result Image

视图需要所有 ApplicationRoles(包含所有子角色)且未经过滤,因为我将在调用视图时使用过滤器。

如何在没有 where 语句的情况下更改 CTE?

我以这个为例。但它只返回“管理员”的直接子元素 我也从 Childs 中搜索 Child。

WITH recursiveTable(ParentApplicationRoleId, ChildApplicationRoleId)
AS
(
    SELECT ParentApplicationRoleId, ChildApplicationRoleId
        FROM ApplicationRoleParentChild
    UNION ALL
    SELECT ApplicationRoleParentChild.ParentApplicationRoleId, ApplicationRoleParentChild.ChildApplicationRoleId
        FROM ApplicationRoleParentChild
        INNER JOIN recursiveTable ON ApplicationRoleParentChild.ParentApplicationRoleId = recursiveTable.ChildApplicationRoleId   
)
/* Get all Childelements (from recursive Table) and add the ParentRoleId to this List */
    SELECT ApplicationRole.Name AS ChildRoleName, Parent.Name AS ParentRoleName
    FROM recursiveTable
    INNER JOIN ApplicationRole ON ApplicationRole.ApplicationRoleId = recursiveTable.ChildApplicationRoleId 
    INNER JOIN ApplicationRole as Parent ON Parent.ApplicationRoleId = recursiveTable.ParentApplicationRoleId 

/*The Query-Filter when i call the View: Like SELECT * FROM View WHERE Parent.Name = 'Administrator'
    Expected Returns: Role1-10, Departement1-3 and Administrator
    Current Returns: Only direct Childs (Role2,7,8, Departement1,3)

    Departement2 is Child of Departement1
    And some other Roles are in one of the Departements or roles
*/

表: ApplicationRole(所有角色) ApplicationRoleParentChild(所有父子关系)(具有 FK 父和 FK 子角色)

我希望有人可以帮助我。

谢谢

【问题讨论】:

WHERE ParentApplicationRoleId is NULL ?第一个选择 - ***,第二个选择 - 树展开。 是的,使用 cte 是正确的 - 定义***的 where 子句 【参考方案1】:

yor where 子句过滤所有记录。和更深的记录没有直接的父管理员。 要按它进行过滤,您可以将***记录名称存储为 cte 中的列

WITH recursiveTable(ParentApplicationRoleId, ChildApplicationRoleId, TopLevelName)
AS
(
    SELECT ParentApplicationRoleId, ChildApplicationRoleId, Name
        FROM ApplicationRoleParentChild
    UNION ALL
    SELECT ApplicationRoleParentChild.ParentApplicationRoleId, ApplicationRoleParentChild.ChildApplicationRoleId
        , recursiveTable.TopLevelName
        FROM ApplicationRoleParentChild
        INNER JOIN recursiveTable ON ApplicationRoleParentChild.ParentApplicationRoleId = recursiveTable.ChildApplicationRoleId   
)

或者你甚至可以建立孩子的完整路径

   WITH recursiveTable(ParentApplicationRoleId, ChildApplicationRoleId, TopLevelName)
    AS
    (
        SELECT ParentApplicationRoleId, ChildApplicationRoleId, cast(Name as varchar(1000))
            FROM ApplicationRoleParentChild

        UNION ALL
        SELECT ApplicationRoleParentChild.ParentApplicationRoleId, ApplicationRoleParentChild.ChildApplicationRoleId
            , left(recursiveTable.TopLevelName + '/' + name, 1000)
            FROM ApplicationRoleParentChild
            INNER JOIN recursiveTable ON ApplicationRoleParentChild.ParentApplicationRoleId = recursiveTable.ChildApplicationRoleId   
    )

然后像where Parent.TopLevelName like '%Administrator%'一样过滤

更新 如通知 Ivan Starostin 在他的评论中 如果您不想将每条记录的所有层次结构组合作为***。 您必须为 cte 中的第一个选择添加 where 子句以定义***节点。 类似ParentApplicationRoleId is NULLParentApplicationRoleId = ''

【讨论】:

以上是关于sql递归cte在视图中不能正常工作的主要内容,如果未能解决你的问题,请参考以下文章

将 PostgreSQL 递归 CTE 转换为 SQL Server

SQL Server CTE 递归查询全解

sql server中的cte

sql server使用cte递归查询获取树形的父节点/子节点

SQL 递归查询,意淫CTE递归的执行步骤

SQL 多条件 CTE 递归