2009-12-24 65 views
1

我们的业务是分层销售人员关系,有时也称为全层。它3深。从单个表格中提取3层相关数据

用英语:Salesman-A-tier有他们下的人,我们称他们为推销员-B-层,而B-tier在他们的推销员C-层中有推销员。

表:

id, name, agentId 
1011, bob, 0 
1012, jim, 1011 
1013, tim, 1011 
1014, sam, 1011 
1015, dav, 1013 
1016, kim, 1013 
1017, sal, 1015 
1018, vin, 1015 

(ID是代理的标识,被称为的agentId领域是salesmans上游剂)

我需要的是在所有这一切下的推销员的列表(案例鲍勃或编号= 1011),3层深。

我已经得到了2级的深度,但之后得到了抑制。 找到一个更好的方法我看不到我自己,我寻求帮助。

我的SQL至今:

选择c.id,c.name,c.agentId从 推销员S其中s.agentId = 1011或 s.agentId =(从 选择ss.agentId推销员ss其中ss.id = s.agentid)

这让我2层深,但我不能得到第三。

任何帮助表示赞赏。 在此先感谢, 马修

+1

这不能解决你的问题,但你真的应该考虑规范化你的表,这样你就不必为这样简单的数据做枯燥乏味的查询。 拔出业务代表id并制作一个只有id和业务代表id的表。 – 2009-12-24 01:59:10

+1

这是干什么用的数据库? – 2009-12-24 02:25:24

回答

0

在这里一个简单的选择将使用递归CTE。确保你用分号完成了前面的陈述。

with recCTE as 
(
/* Base case first */ 
SELECT 1 as theLevel, * 
FROM theTable 
WHERE AgentID = 0 

/* Recurisve bit */ 
UNION ALL 

SELECT r.theLevel + 1, t.* 
FROM recCTE r 
JOIN theTable t 
ON r.ID = r.AgentID 
) 
SELECT * 
FROM recCTE 
WHERE theLevel <= 3; 
0

我知道,这往往是一个痛苦(或几乎是不可能的)重新构建一个表像,但如果这是一个选项,那么你应该在SQL退房Joe Celko's book on trees and hierarchies。他有一些可供选择的表格设计,例如嵌套集合模型,它可以使您的查询变得琐碎。 Here's我能从Google找到的一个简单示例。

除非重新设计,如果你在MS SQL Server 2005或更高,那么你可以使用热膨胀系数为罗布建议是。我不知道其他RDBMS可能提供的递归函数(如果有的话)。

1

直SQL-92溶液,避免两个递归(不是普遍实现)和供应商特定的特征(对于通常的原因):

select 
    theAnswer.* 
from 
    salesmen s0 
    join 
    salesmen s1 on s0.id in (s1.id, s1.agentId) 
    join 
    salesmen theAnswer on s1.id = theAnswer.agentId 
where 
    0 = s0.agentId 
    and 
    1011 in (s0.id, s1.id) 

这里的假设是,感兴趣的销售人员(id = 1011这种情况)可能是A层或B层。要限制查询仅在A-层开始搜索,替换最后一行:

1011 = s0.id 

另一个假设是,有每个销售人员的具体哪一行(idUNIQUE),这意味着任何给定的销售人员有一个agentId。如果不是这样,与替换的第一行:

select distinct 

我要指出,有四个层次的样本数据,而不是三个按问题陈述。

  • A-层:bob
  • B-层:jimtimsam
  • C-层:davkim
  • d层:salvin

即原来的查询变成:

select 
    theAnswer.* 
from 
    salesmen s0 
    join 
    salesmen s1 on s0.id in (s1.id, s1.agentId) 
    join 
    salesmen s2 on s1.id in (s2.id, s2.agentId) 
    join 
    salesmen theAnswer on s2.id = theAnswer.agentId 
where 
    0 = s1.agentId 
    and 
    1011 in (s0.id, s1.id, s2.id) 
    and 
    (s0.id = s1.id or s1.id <> s2.id) 

最后一行的目的是为了避免把查询到select distinct,是一个简单的减少:

(
     s0.id = s1.id and s1.id = s2.id 
     or 
     s0.id = s1.id and s1.id <> s2.id 
     or 
     s0.id <> s1.id and s1.id <> s2.id 
    ) 

要到5级层次,只需要比较第一次和第二次查询以查看模式出现。

  • FROM子句获得额外的JOIN
  • 最后的JOIN必须与这个新的JOIN比较。
  • WHERE子句的第二部分会获得一个额外的项目。
  • WHERE条款的最后一部分建立在片段繁体字以上通过增加一个额外OR条件做处理额外的比较,对新JOIN,继=<>者作出的模式。
+0

我认为你的代码示例在这里很好,但我仍然担心这是一个糟糕的选择,如何存储和访问这些数据。这些查询不仅不必要地复杂,而且也不会扩展 - 如果添加了第五个级别,该怎么办? – ewall 2009-12-24 20:32:34

2

如果您正在使用SQL Server 2008中或者您可以使用SQL Server 2008 - HIERARCHYID数据类型在SQL Server 2008可以非常轻松地解决你的问题。检查下面的这些参考。

Reference 1

Reference 2

下面是如何存储HierarchyId的全方位分层信息的视觉表示。 alt text http://magmainteractive.net/tutorials/image.axd?picture=WindowsLiveWriter/IntroductiontotheSQLServer2008HIERARCHYI_10473/image_thumb_3.png

+1

+1分享我以前没见过的东西。凉! – ewall 2009-12-24 20:33:28