具有Where子句的递归CTE不返回所有结果

时间:2014-09-08 12:07:40

标签: sql sql-server recursion

我有一个像这样的UserTypes表:

UserTypeID | ParentUserTypeID | Name
1            NULL               Person
2            NULL               Company
3            2                  IT
4            3                  Accounting Software

我想要做的是在将UserTypeID传递给CTE时获取所有ParentUserTypeID。到目前为止我已经得到了它,但它只返回一个ParentUserTypeID而不是树中的所有。{/ p>

   ;WITH CTE 
    AS
    (
    SELECT 
        c1.ParentUserTypeID,
        c1.UserTypeID,
        c1.Name
    FROM 
        dbo.UserTypes c1
    WHERE 
        ParentUserTypeID IS NULL

    UNION ALL

    SELECT 
        c2.ParentUserTypeID,
        c2.UserTypeID,
        c2.Name 
    FROM 
        dbo.UserTypes c2
        INNER JOIN CTE
        ON c2.ParentUserTypeID = CTE.UserTypeID
    )
    SELECT 
        ParentUserTypeID,
        UserTypeID
    FROM 
        CTE
    WHERE
        UserTypeID = 4

我得到的结果是:

UserTypeID  | ParentUserTypeID  
4             3

修改/更新

我真正需要的是与指定的UserTypeID关联的层次结构树中的所有@UserTypeID的列表。有点像这样:

UserTypeID | ParentUserTypeID
2            NULL
3            2
4            3

然后我可以使用我的应用程序循环遍历这个并插入UserID以及适用的UserTypeID:

<cfloop query="rsUserTypeIDs"> // loops around the UserTypeIDs brought back from the CTE
INSERT INTO dbo.User_UserType (UserID, UserTypeID)
VALUES
(
#UserID#                    // Provided by the web application
#rsUserTypeIDs.UserTypeID#  // Each time it loops it gets the UserTypeID from the CTE
)  
</cfloop>

上述代码与此问题无关。我把它放在那里让你明白我在做CTE的结果。

如何更正递归CTE,以便将UserTypeID一直返回到树顶部而不是仅显示其直接ParentUserTypeID的一行?

3 个答案:

答案 0 :(得分:3)

我不知道您允许/希望更改结构的程度,但您可能需要定义您在CTE根目录中查找的UserTypeID,例如:

;WITH CTE 
AS
(
SELECT 
    c1.ParentUserTypeID,
    c1.UserTypeID,
    c1.Name
FROM 
    dbo.UserTypes c1
WHERE 
    UserTypeID = 4

UNION ALL

SELECT 
    c2.ParentUserTypeID,
    c2.UserTypeID,
    c2.Name 
FROM 
    dbo.UserTypes c2
    INNER JOIN CTE
    ON c2.UserTypeID = CTE.ParentUserTypeID
)
SELECT 
    ParentUserTypeID,
    UserTypeID
FROM 
    CTE

SQL Fiddle results

答案 1 :(得分:1)

SQL Fiddle

MS SQL Server 2012架构设置

CREATE TABLE UserTypes
(
  UserTypeId INT PRIMARY KEY,
  ParentUserTypeId INT NULL,
  Name VARCHAR(50)
 )


INSERT INTO UserTypes
VALUES
    (1,NULL, 'Person'),
    (2, NULL, 'Company'),
    (3,2, 'IT'),
    (4,3,'Accounting Software')

查询1

WITH CTE
AS
(
  SELECT 
        c1.ParentUserTypeID,
        c1.UserTypeID,
        c1.Name, 
        1 as Level
    FROM 
        UserTypes c1
    WHERE 
        UserTypeId =4

  UNION ALL

  SELECT 
        c2.ParentUserTypeID,
        c2.UserTypeId,
        c2.Name,
        CTE.Level + 1 As Level
  FROM UserTypes c2
  INNER JOIN CTE 
    ON CTE.ParentUserTypeID = C2.UserTypeId
)
SELECT UserTypeId, ParentUserTypeID
FROM CTE
ORDER BY Level Desc

<强> Results

| USERTYPEID | PARENTUSERTYPEID |
|------------|------------------|
|          2 |           (null) |
|          3 |                2 |
|          4 |                3 |

答案 2 :(得分:0)

尝试将查询更改为:

WITH CTE 
AS
(
SELECT 
    c1.ParentUserTypeID,
    c1.UserTypeID,
    c1.Name
FROM 
    dbo.Company c1
WHERE 
    ParentUserTypeID IS NULL

UNION ALL

SELECT 
    CTE.ParentUserTypeID,
    c2.UserTypeID,
    c2.Name 
FROM 
    dbo.Company c2
    INNER JOIN CTE
    ON c2.ParentUserTypeID = CTE.UserTypeID
)
SELECT 
    ParentUserTypeID,
    UserTypeID,
FROM 
    CTE
WHERE
    UserTypeID = 4

在union子句中使用CTE.ParentUserTypeID而不是c2.ParentUserTypeID。否则,在递归中添加相同的行。