如何从SQL表中检索分层数据

时间:2016-04-25 10:30:44

标签: sql hierarchy

我有2个表:T_Employees和T_Projects

每个项目都分配了不同数量的员工。我需要做的是获得每个员工的层次结构,分配给特定项目。

查看下图和预期结果。

如何在Microsoft SQL Server 2008R2上完成此操作?

enter image description here

CREATE TABLE [dbo].[T_Projects](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ProjectId] [int] NOT NULL,
    [EmployeeId] [int] NOT NULL,
    CONSTRAINT [PK_T_Projects] PRIMARY KEY CLUSTERED([ID] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY] 
GO

SET IDENTITY_INSERT [dbo].[T_Projects] ON
INSERT [dbo].[T_Projects] ([ID], [ProjectId], [EmployeeId]) VALUES (1, 456,10)
INSERT [dbo].[T_Projects] ([ID], [ProjectId], [EmployeeId]) VALUES (2, 456, 12)
INSERT [dbo].[T_Projects] ([ID], [ProjectId], [EmployeeId]) VALUES (3, 23, 11)
SET IDENTITY_INSERT [dbo].[T_Projects] OFF

CREATE TABLE [dbo].[T_Employees](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Level] [int] NOT NULL,
    [Employee] [nvarchar](256) NOT NULL,
    [Department] [nvarchar](5) NOT NULL,
    [MasterId] [int] NULL,
    [Code] [nvarchar](10) NOT NULL,
    [Note] [nvarchar](100) NULL,
    CONSTRAINT [PK_T_Employees] PRIMARY KEY CLUSTERED ([ID] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]
GO

SET IDENTITY_INSERT [dbo].[T_Employees] ON
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (1, 1, N'Thomas S.', N'A', NULL, N'1-4', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (2, 1, N'Michael F.', N'A', NULL, N'1-5', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (3, 1, N'Simone S.', N'A', NULL, N'1-3', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (4, 2, N'Stefan K.', N'B', 1, N'2-18', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (5, 2, N'Mike T.', N'B', 2, N'2-96', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (6, 2, N'Loris P.', N'B', 3, N'2-15', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (7, 3, N'Lennon I.', N'B', 4, N'2-19', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (8, 3, N'Kerim K.', N'C', 4, N'2-66', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (9, 3, N'Ilmas Y.', N'C', 6, N'2-59', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (10, 4, N'Innes Y.', N'D', 8, N'3-89', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (11, 4, N'Andreas U.', N'E', 7, N'3-63', NULL)
INSERT [dbo].[T_Employees] ([ID], [Level], [Employee], [Department], [MasterId], [Code], [Note]) VALUES (12, 4, N'Fatih O.', N'I', 9, N'3-32', NULL)
SET IDENTITY_INSERT [dbo].[T_Employees] OFF

2 个答案:

答案 0 :(得分:2)

您可以使用递归CTE遍历层次结构

这是经典的自上而下CTE:

WITH EmployeesHierarchy AS
(
    SELECT ID,[Level],Employee,Department,Code,MasterId
    FROM T_Employees
    WHERE [Level]=1
    UNION ALL
    SELECT nextLevel.ID,nextLevel.[Level],nextLevel.Employee,nextLevel.Department,nextLevel.Code,nextLevel.MasterId
    FROM EmployeesHierarchy AS recCall
    INNER JOIN T_Employees AS nextLevel ON nextLevel.[Level]=recCall.[Level]+1 AND nextLevel.MasterId=recCall.ID
)
SELECT * FROM EmployeesHierarchy
ORDER BY [Level],MasterId
GO

现在反过来说:我从项目中提到的员工开始,然后向上移动列表,直到没有parentId为止。项目在CTE第一部分获得的数据刚刚通过,显示在所有行中。

WITH EmployeesHierarchy AS
(
    SELECT p.ID AS p_ID,p.ProjectId,e.ID AS e_ID,[Level],e.Employee,e.Department,e.Code,e.MasterId
    FROM T_Projects AS p 
        INNER JOIN T_Employees AS e ON p.EmployeeId=e.ID
    UNION ALL
    SELECT recCall.p_ID,recCall.ProjectId,nextLevel.ID,nextLevel.[Level],nextLevel.Employee,nextLevel.Department,nextLevel.Code,nextLevel.MasterId
    FROM EmployeesHierarchy AS recCall
    INNER JOIN T_Employees AS nextLevel ON nextLevel.ID=recCall.MasterId
)
SELECT * FROM EmployeesHierarchy
--WHERE ProjectId=456
ORDER BY [Level]

结果

+------+-----------+------+-------+------------+------------+------+----------+
| p_ID | ProjectId | e_ID | Level | Employee   | Department | Code | MasterId |
+------+-----------+------+-------+------------+------------+------+----------+
| 3    | 23        | 1    | 1     | Thomas S.  | A          | 1-4  | NULL     |
+------+-----------+------+-------+------------+------------+------+----------+
| 2    | 456       | 3    | 1     | Simone S.  | A          | 1-3  | NULL     |
+------+-----------+------+-------+------------+------------+------+----------+
| 1    | 456       | 1    | 1     | Thomas S.  | A          | 1-4  | NULL     |
+------+-----------+------+-------+------------+------------+------+----------+
| 2    | 456       | 6    | 2     | Loris P.   | B          | 2-15 | 3        |
+------+-----------+------+-------+------------+------------+------+----------+
| 1    | 456       | 4    | 2     | Stefan K.  | B          | 2-18 | 1        |
+------+-----------+------+-------+------------+------------+------+----------+
| 3    | 23        | 4    | 2     | Stefan K.  | B          | 2-18 | 1        |
+------+-----------+------+-------+------------+------------+------+----------+
| 3    | 23        | 7    | 3     | Lennon I.  | B          | 2-19 | 4        |
+------+-----------+------+-------+------------+------------+------+----------+
| 1    | 456       | 8    | 3     | Kerim K.   | C          | 2-66 | 4        |
+------+-----------+------+-------+------------+------------+------+----------+
| 2    | 456       | 9    | 3     | Ilmas Y.   | C          | 2-59 | 6        |
+------+-----------+------+-------+------------+------------+------+----------+
| 1    | 456       | 10   | 4     | Innes Y.   | D          | 3-89 | 8        |
+------+-----------+------+-------+------------+------------+------+----------+
| 2    | 456       | 12   | 4     | Fatih O.   | I          | 3-32 | 9        |
+------+-----------+------+-------+------------+------------+------+----------+
| 3    | 23        | 11   | 4     | Andreas U. | E          | 3-63 | 7        |
+------+-----------+------+-------+------------+------------+------+----------+

答案 1 :(得分:0)

您的结果数据集可以运行此查询:

declare @project int ;
declare cur_project cursor for 
select distinct ProjectId from T_Projects;

open cur_project
fetch next from cur_project into @project
while @@FETCH_STATUS = 0
begin
select E.* from [dbo].[T_Projects] P
inner join [dbo].[T_Employees] E
on P.EmployeeId = E.ID
where P.ProjectId = @project

fetch next from cur_project into @project
end
close cur_project;
deallocate cur_project;