从单个表中提取3层相关数据

时间:2009-12-24 01:52:51

标签: sql

我们的业务是一个分层的销售员关系,有时称为全方位层。它的3深。

英文版:Salesman-A-tier有人在他们之下,我们称他们为推销员-B-tier,b-tier有推销员,他们是推销员-C-tier。

表:

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是代理商的Id,名为agentId的字段是salesmans上游代理商)

我需要的是所有销售人员的名单(在这种情况下为bob或id = 1011),3层深。

我已经达到了2级,但在那之后受到了限制。 认为这是一个更好的方法,我看不到自己,我正在寻求帮助。

到目前为止我的sql:

  

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

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

任何帮助表示赞赏。 提前致谢, 马修

4 个答案:

答案 0 :(得分:2)

如果您正在使用 SQL Server 2008 ,或者如果您可以使用SQL Server 2008 - HierarchyId ,则SQL Server 2008中的数据类型可以非常轻松地解决您的问题。请查看以下这些参考资料。

Reference 1

Reference 2

以下是HierarchyId如何存储 omni-tiered 信息的直观表示。 alt text http://magmainteractive.net/tutorials/image.axd?picture=WindowsLiveWriter/IntroductiontotheSQLServer2008HIERARCHYI_10473/image_thumb_3.png

答案 1 :(得分: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-tier:bob
  • B层:jimtimsam
  • C-tier:davkim
  • D-tier: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的额外比较,遵循由=<>运营商。

答案 2 :(得分: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;

答案 3 :(得分:0)

我知道重新架构这样的表通常很痛苦(或几乎不可能),但如果这是一个选项,那么你应该在SQL中查看Joe Celko's book on trees and hierarchies。他有一些替代表设计,比如嵌套集模型,它可以使你的查询变得微不足道。 Here's我可以从Google找到的一个简短示例。

除非重新设计,否则如果您使用的是MS SQL Server 2005或更高版本,则可以使用CT建议。我不知道其他RDBMS可能提供的递归函数(如果有的话)。