遍历记录以构建层次结构

时间:2018-10-22 12:10:18

标签: tsql sql-server-2012

请考虑下表。他们描述了学校的等级制度和每个学生的笔记。

users
-------------------------------------------------------------
root_id    obj_id    obj_type    obj_ref_id    obj_role
-------------------------------------------------------------
1          2         student     7             learn   
1          3         student     7             learn
1          1         principal   1             lead
1          4         mentor      1             train teachers
1          5         trainee     4             learn teaching
1          6         trainee     4             learn teaching
1          7         teacher     1             teach
2          8         student     9             learn
2          9         principal   9             lead

notes
--------------------------------------------------------------
note_id    obj_id    note
--------------------------------------------------------------
1          2         foo
2          2         bar
3          2         baz
4          3         lorem
5          8         ipsum

我需要写出每个用户的注释的层次结构和数量,如下所示:

-------------------------------------------------------------------------------------------
obj_id   notes  obj_path
-------------------------------------------------------------------------------------------
1        0      principal 1 (lead)
2        3      student 2 (learn) > teacher 7 (teach) > principal 1 (lead)
3        1      student 3 (learn) > teacher 7 (teach) > principal 1 (lead)
4        0      mentor 4 (train teachers) > principal 1 (lead)
5        0      trainee 5 (learn teaching) > mentor 4 (train teachers) > principal 1 (lead)
6        0      trainee 6 (learn teaching) > mentor 4 (train teachers) > principal 1 (lead)
7        0      teacher 7 (teach) > principal 1 (lead)
8        1      student 8 (learn) > principal 2 (lead)
9        0      principal 9 (lead)

为此,我了解到我需要使用如下循环:

declare cur cursor for 
select obj_id from users order by root_id 
open cur
declare @obj_id int
    fetch next from cur into @id
    while (@@FETCH_STATUS = 0)
    begin
        select obj_role from users where obj_id = @obj_id
        fetch next from cur into @obj_id
    end
close cur
deallocate cur

这是我到目前为止所拥有的,但是我不知道如何从这里开始。有人可以帮我吗?

1 个答案:

答案 0 :(得分:0)

了解使用光标将逐个处理每个记录。

递归CTE将是更好的解决方案:

类似的东西:

DECLARE @User TABLE
    (
        [root_id] INT
      , [obj_id] INT
      , [Obj_type] NVARCHAR(100)
      , [obj_ref_id] INT
      , [obj_role] NVARCHAR(100)
    );

DECLARE @Notes TABLE
    (
        [note_id] INT
      , [obj_id] INT
      , [note] NVARCHAR(255)
    );

INSERT INTO @Notes (
                       [note_id]
                     , [obj_id]
                     , [note]
                   )
VALUES ( 1, 2, 'foo  ' )
     , ( 2, 2, 'bar  ' )
     , ( 3, 2, 'baz  ' )
     , ( 4, 3, 'lorem' )
     , ( 5, 8, 'ipsum' );


INSERT INTO @User (
                      [root_id]
                    , [obj_id]
                    , [Obj_type]
                    , [obj_ref_id]
                    , [obj_role]
                  )
VALUES ( 1, 2, 'student', 7, 'learn' )
     , ( 1, 3, 'student', 7, 'learn' )
     , ( 1, 1, 'principal', 1, 'lead' )
     , ( 1, 4, 'mentor', 1, 'train teachers' )
     , ( 1, 5, 'trainee', 4, 'learn teaching' )
     , ( 1, 6, 'trainee', 4, 'learn teaching' )
     , ( 1, 7, 'teacher', 1, 'teach' )
     , ( 2, 8, 'student', 9, 'learn' )
     , ( 2, 9, 'principal', 9, 'lead' );

WITH [Hierarchy]
AS ( SELECT [obj_id] AS [root_obj]
          , [obj_ref_id] AS [root_obj_ref]
          , [obj_id]
          , [obj_ref_id]
          , CONVERT(
                       NVARCHAR(MAX)
                     , [Obj_type] + ' ' + CONVERT(NVARCHAR, [obj_id]) + ' ('
                       + [obj_role] + ')'
                   ) AS [obj_path]
     FROM   @User
     UNION ALL
     SELECT     [a].[root_obj]
              , [a].[root_obj_ref]
              , [b].[obj_id]
              , [b].[obj_ref_id]
              , [a].[obj_path] + ' > ' + [b].[Obj_type]
                + CONVERT(NVARCHAR, [b].[obj_id]) + ' (' + [b].[obj_role] + ')' AS [obj_path]
     FROM       [Hierarchy] [a]
     INNER JOIN @User [b]
         ON [b].[obj_id] = [a].[obj_ref_id]
     WHERE      [a].[obj_id] <> [a].[obj_ref_id] ) --Here, basically continue the recursion while the record isn't referencing itself. The final will include that self referencing record.
SELECT   [Hierarchy].[root_obj] AS [obj_id]
       , (
             SELECT COUNT(*)
             FROM   @Notes
             WHERE  [obj_id] = [Hierarchy].[root_obj]
         ) AS [notes] --Here we'll go out and get the count of notes.
       , [Hierarchy].[obj_path]
FROM     [Hierarchy]
WHERE    [Hierarchy].[obj_id] = [Hierarchy].[obj_ref_id]  --Then we only went those records built up to the final record that was referencing itself.
ORDER BY [Hierarchy].[root_obj];