分类: WINDOWS
2010-02-10 01:26:57
同样的,如果您的企业为具有组织机构格局的客户服务,那么每一个个体都可能是另一个大机构或部门的子机构。最小的客户团体可能是一个子部门,然后一直向上到其对应的上级部门,再到几个部门的集合体,再到一个大的市场,区域,公司最后直到整个集团。
您的报表和分析结果经常需要把这些相关联的记录进行整合分组。举一个较为常见的例子:一般查看一个销售经理的销售情况,也都连带着他下面所有的销售人员的销售情况一起查看了。
因为每条记录对应的父记录的数量不同,因此在SQL语句中处理这种递归关系比较困难;很多时候人们会把这种情况作为一种不平衡或不规则的层次结构来看待。例如,让我们回顾一个非常小的"employees"表格:
CREATE TABLE [dbo].[Employees]( [EmployeeID] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](20) NOT NULL, [Title] [nvarchar](30) NULL, [ReportsTo] [int] NULL CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ( [EmployeeID] ASC ) ) ALTER TABLE [dbo].[Employees] ADD CONSTRAINT [FK_Employees_Employees1] FOREIGN KEY([ReportsTo]) REFERENCES [dbo].[Employees] ([EmployeeID]) |
比方说我们在表中只有四条记录,如下表:
在这个假设的组织机构里面,Andrew 是这里的“一把手”,因为他没有直接主管,所以他没有对应的父级记录;Janet 的记录对应有一个父级记录,Margaret的记录对应有两个父级记录,Steven的记录对应有三个父级记录。
怎样才能够从这张员工表里面得到一个组织关系的图表?比如我们想要查询Steven和他的直接上级的记录。这只是一个简单的关系,语句如下:
SELECT a.EmployeeID, a.Name, a.Title, b.Name AS SupervisorName, a.ReportsTo FROM Employees a LEFT JOIN Employees b ON a.ReportsTo = b.EmployeeID WHERE a.EmployeeID = 5 |
但是,这里我们仅仅看到了Steven 和Margaret。要想在这个层次结构里面获得下一个人员的记录,就不得不对Employees表进行两次自身关联。如果想要得到完整的层级记录那就得对Employees表进行三次自身关联;
语句如下:
SELECT a.EmployeeID, a.Name, a.Title, b.Name AS SupervisorName, c.Name AS NextSupervisorName, d.Name AS TopSupervisorName FROM Employees a LEFT JOIN Employees b ON a.ReportsTo = b.EmployeeID LEFT JOIN Employees c ON b.ReportsTo = c.EmployeeID LEFT JOIN Employees d ON c.ReportsTo = d.EmployeeID WHERE a.EmployeeID = 5 |
查询结果:
上面的语句在小型公司里面是可以正常工作的,但是很明显,要想使用SQL语句快速方便的在一个具有递归关系的组织机构里面对成员进行查找是很困难的。如果我们要想查询Steven的销售情况,连同他所属的每一个上司的销售情况,那么查询就会变得越来越笨重。对于每一个管理者,我们的查询都要包括他自己的销售情况,和他所有下属的销售情况。例如:
SELECT (SELECT COUNT(*) FROM employees a1 INNER JOIN orders b ON a1.employeeid = b.employeeid WHERE a1.employeeid = a.employeeid) AS [steven's sales], (SELECT COUNT(*) FROM employees a1 INNER JOIN orders b ON a1.employeeid = b.employeeid WHERE a1.employeeid = a2.employeeid OR a1.employeeid = a.employeeid) AS [margaret's sales], (SELECT COUNT(*) FROM employees a1 INNER JOIN orders b ON a1.employeeid = b.employeeid WHERE a1.employeeid = a3.employeeid OR a1.employeeid = a.employeeid OR a1.employeeid = a2.employeeid OR a1.employeeid = a3.employeeid) AS [janet's sales], (SELECT COUNT(*) FROM employees a1 INNER JOIN orders b ON a1.employeeid = b.employeeid WHERE a1.employeeid = a4.employeeid OR a1.employeeid = a.employeeid OR a1.employeeid = a2.employeeid OR a1.employeeid = a3.employeeid OR a1.employeeid = a4.employeeid) AS [andrew's sales] FROM employees a INNER JOIN employees a2 ON a.reportsto = a2.employeeid INNER JOIN employees a3 ON a2.reportsto=a3.employeeid INNER JOIN employees a4 ON a3.reportsto=a4.employeeid WHERE a.employeeid = 5 |
(译者注:在SQL SERVER 2005及其以上版本中已经支持了递归查询,有兴趣的读者可以参考“with as()”语法。)