sql - 'exists' 相关子查询中递归 CTE 的替代方案?

标签 sql sql-server-2005 recursion common-table-expression correlated-subquery

我有一种情况,我需要能够查看给定的人是否在用户/经理层次结构中。

我需要能够根据一组规则为一组用户执行此操作(不要担心这一点,只是为了给它一些上下文)

理想情况下,我想在 where 子句的相关存在子查询中使用递归 CTE。

但这会带来很多问题..

  • 我认为您根本不能在子查询中使用 CTE。
  • 我在 SQL 2005 上使用兼容模式 80 - 所以我不能使用交叉应用......所以我没有列参数到 UDF 中 :-(

  • 我想我想做的是:
    WITH UserHierarchy(UserId, ManagerId)
        AS
        (
            --Anchor Definition
            SELECT [UserId], [ManagerId] FROM [Users] WHERE [ManagerId] = [Rules].[RuleAddedByUserId] -- this needs to bind to an outer query....
            UNION ALL
            --Recursive Member definiation
            SELECT [Users].[UserId], [Users].[ManagerId] FROM [Users] 
            INNER JOIN [UserHierarchy] ON [Users].[ManagerId] = [UserHierarchy].[UserId]
            WHERE [Users].[UserId] <> [Users].[ManagerId] --don't recurse if the anchor definition matches itself (to avoid an infinate loop).
        )
    

    无论如何,是否可以在兼容模式 80 中使 anchor 定义动态?或者另一种方法?

    最佳答案

    一种方法是创建一个递归 CTE,对于每个用户,树中该用户的每个祖先都有一行。然后您可以使用 CTE 过滤祖先。例如,对于这棵树:

    Bob
    |-Alice
      |-Jim
    

    CTE 将返回如下内容:
    User  Ancestor Level
    ----  -------- -----
    Bob   NULL     1
    Alice Bob      1
    Jim   Alice    1
    Jim   Bob      2
    
    Level列最终不是很重要,但我发现它在我编写查询时很有帮助。

    这是一个示例脚本,用于标识层次结构中 Alice 下的所有用户:
    CREATE TABLE Users(
        UserId int NOT NULL PRIMARY KEY,
        Name nvarchar(25),
        ManagerId int
    );
    GO
    
    INSERT INTO Users (UserId, Name, ManagerId)
    SELECT 1, 'Bob', NULL UNION ALL
    SELECT 2, 'Steve', 1 UNION ALL
    SELECT 3, 'Chris', 2 UNION ALL
    SELECT 4, 'Alice', 1 UNION ALL
    SELECT 5, 'Roger', 4 UNION ALL
    SELECT 6, 'Tony', 5;
    GO
    
    WITH all_ancestors AS (
        SELECT
            u.UserId,
            u.Name,
            u.ManagerId AS AncestorId,
            1 AS level
        FROM
            Users AS u
        UNION ALL
        SELECT
            alla.UserId,
            alla.Name,
            u.ManagerId AS AncestorId,
            alla.level + 1
        FROM
                all_ancestors AS alla
            INNER JOIN
                Users AS u
            ON
                alla.AncestorId = u.UserId
    )
    SELECT
        u.*
    FROM
            Users AS u
        INNER JOIN
            all_ancestors AS a
        ON
            u.UserId = a.UserId
    WHERE
        a.AncestorId = 4; -- Alice
    GO
    
    DROP TABLE Users;
    GO
    

    关于sql - 'exists' 相关子查询中递归 CTE 的替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8340423/

    相关文章:

    sql - SQL Server 中的算术溢出

    sql - 使用 SQL 中的过程从存储表行中删除空间

    c - 使用递归的斐波那契

    javascript - 左关联二叉树折叠

    asp.net - 如何在 mysql 查询中用“替换”?

    java - JPA 命名查询显示错误

    sql - 左连接ON非空列不能选择非空列

    sql - 如何在 SQL GROUP BY 子句中返回空组

    algorithm - 使用递归的可能分类

    mysql - 计数为一个查询的两个选择查询