需要有关SQL CTE查询的帮助

时间:2010-05-21 12:29:47

标签: sql sql-server sql-server-2005 recursion

我有一个表,我需要从视图中获取一些特定数据。这是包含一些示例数据的基表结构:

| UserID | ReportsToUserID | Org ID |
-------------------------------------
|    1   |      NULL       |    1   |
-------------------------------------
|    2   |       1         |    1   |
-------------------------------------
|    3   |       2         |    1   |
-------------------------------------
|    4   |       3         |    1   |
-------------------------------------

用户将输入报告,用户可以查看向其报告的用户以及向这些用户报告的任何用户的报告。向任何人报告的用户都可以看到他们组织中的所有内容根据上面的示例数据,用户1可以看到2,3,和2的报告。 4;用户2可以看到3& 4;用户3可以看到4的报告。

对于视图,我希望返回的数据如下:

    | UserID | CanSeeUserID           |  OrgID |
    --------------------------------------------
    |    1   |      2                 |    1   |
    --------------------------------------------
    |    1   |      3                 |    1   |
    --------------------------------------------
    |    1   |      4                 |    1   |
    --------------------------------------------
    |    2   |      3                 |    1   |
    --------------------------------------------
    etc...

以下是我目前的代码,非常感谢任何帮助。

WITH CTEUsers (UserID, CanSeeUserID, OrgID)
AS
(
    SELECT e.ID, e.ReportsToUserID, e.OrgID
    FROM Users e WITH(NOLOCK)
    WHERE COALESCE(ReportsToUserID,0) = 0 --ReportsToUserID can be NULL or 0
    UNION ALL

    SELECT e.ReportsToUserID, e.ID,e.OrgID
    FROM Users e WITH(NOLOCK)
    JOIN CTEUsers c
        ON e.ID = c.UserID
)
SELECT * FROM CTEUsers

4 个答案:

答案 0 :(得分:1)

我知道它并不漂亮,但我快速查看的唯一方法是在分层查询上运行光标。聪明的人几乎可以肯定得到比我更好的答案,但是周五下午,我要去酒吧了!

SET NOCOUNT ON;
DECLARE @Users TABLE 
(
    UserID int NOT NULL,
    [Name] varchar(10),
    ReportsToUserID int,
    OrgID int
)

DECLARE @Output TABLE
(
    UserID int,
    CanSeeReportsFrom int
)
INSERT INTO @Users VALUES (1, 'Dan', NULL, 1)
INSERT INTO @Users VALUES (2, 'Tom', 1, 1)
INSERT INTO @Users VALUES (3, 'Dick', 2, 1)
INSERT INTO @Users VALUES (4, 'Harry', 3, 1)

DECLARE @UserID int
DECLARE csr CURSOR FAST_FORWARD FOR
SELECT  COALESCE(UserID, 0)
FROM    @Users

OPEN csr
FETCH NEXT FROM csr INTO @UserID
WHILE (@@FETCH_STATUS = 0)
BEGIN
    ;WITH CTEUsers
    AS
    (
        SELECT  @UserID AS CallingUserID,
                e.UserID, 
                e.ReportsToUserID
        FROM    @Users e
        WHERE   COALESCE(e.ReportsToUserID, 0) = @UserID
        UNION ALL
        SELECT  @UserID,
                e.UserID, 
                e.ReportsToUserID
        FROM @Users e INNER JOIN CTEUsers c ON e.ReportsToUserID = c.UserID
    )
    INSERT INTO @Output 
    SELECT CallingUserID, UserID FROM CTEUsers

    FETCH NEXT FROM csr INTO @UserID
END
CLOSE csr
DEALLOCATE csr
SELECT * FROM @Output

答案 1 :(得分:1)

WITH reports (userid, orgid, [Level])
     AS (SELECT e.userid,
                e.orgid,
                0 AS [Level]
         FROM   users e
         WHERE  Coalesce(reportstouserid, 0) = 0
         UNION ALL
         SELECT e.userid,
                e.orgid,
                [Level] + 1
         FROM   users AS e
                INNER JOIN reports AS d
                  ON d.userid = e.reportstouserid)
-- Statement that executes the CTE
SELECT a.[UserID],
       b.userid [CanSeeUserID],
       a.[OrgID]
FROM   reports a
       JOIN reports b
         ON a.[Level] < b.[Level] 

答案 2 :(得分:1)

我使用以下内容创建一个Temp表,其中包含一些与您相似的数据:

IF OBJECT_ID('tempdb..#Stage1') IS NOT NULL DROP TABLE #Stage1;
GO

WITH CTEFillTemp AS (
SELECT 1 [UserId], NULL [ReportsToUserID], 1 [OrgId] UNION ALL
SELECT 2 [UserId], 1 [ReportsToUserID], 1 [OrgId] UNION ALL
SELECT 3 [UserId], 2 [ReportsToUserID], 1 [OrgId] UNION ALL
SELECT 4 [UserId], NULL [ReportsToUserID], 2 [OrgId] UNION ALL
SELECT 5 [UserId], 3 [ReportsToUserID], 1 [OrgId] UNION ALL
SELECT 6 [UserId], 4 [ReportsToUserID], 2 [OrgId] UNION ALL
SELECT 7 [UserId], 3 [ReportsToUserID], 1 [OrgId]
) SELECT * INTO #Stage1 FROM CTEFillTemp
GO

SELECT * FROM #Stage1
GO

然后我使用了以下查询:

WITH CTE (UserId, CanSeeUserId, OrgId, Level) AS (
    SELECT #Stage1.ReportsToUserId, #Stage1.UserId, #Stage1.[OrgId], 0 [Level] FROM #Stage1
    UNION ALL
    SELECT #Stage1.ReportsToUserId, CTE.CanSeeUserId, CTE.[OrgId], [Level] + 1 FROM #Stage1
    INNER JOIN CTE ON #Stage1.UserId = CTE.UserId AND #Stage1.[OrgId] = CTE.[OrgId]
)
SELECT *
  FROM CTE
 WHERE [UserId] IS NOT NULL
 ORDER BY UserId, [Level]

这应该产生你想要的结果,但是因为它使用递归公用表表达式,它不是无限级别的可靠解决方案。 OPTION (MAXRECURSION 99)虽然可以提供帮助。

答案 3 :(得分:0)

请检查以下查询是否符合您的目的。

Select A.UserID, B.UserID as 'CanSeeID',A.OrgID from 
USERS A
LEFT OUTER JOIN USERS B
ON ( A.ReportstoUserId  is NULL OR A.ReportstoUserId=0 )
OR A.UserId = B.ReportstoUserId