2010-05-21 2 views
0

У меня есть таблица, в которой мне нужно получить некоторые конкретные данные для представления. Вот структура базовой таблицы с некоторыми данными выборки:Нужна помощь с SQL CTE Query

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

Пользователям будут вводить отчеты и пользователи могут просматривать отчеты пользователей, которые сообщают о них и всех пользователей, которые сообщают этим пользователям. Пользователи, которые никому не сообщают, могут видеть все в своей организации. Учитывая мои данные выше, пользователь 1 может видеть отчеты 2, 3, & 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 

ответ

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) может немного помочь.

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 
+0

К сожалению, это не возвращает то, что я ищу. – Chuck

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
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] 
+0

Довольно уверен, что у этого есть! Я собираюсь запустить некоторые тесты и отметьте «принятыми», если они все выглядят хорошо! Благодаря! – Chuck

+0

Только проблема с базированием на уровне состоит в том, что у нас может быть несколько уровней 2 (например), каждый из которых сообщает о них другим уровням 3s. 2s не могут видеть другие 2s прямые отчеты. Однако это полезно, и ответы, по крайней мере, заставляют меня думать по-другому о проблеме. Еще раз спасибо. – Chuck

Смежные вопросы