当表具有指向自身的链接时的 SQL 查询
Posted
技术标签:
【中文标题】当表具有指向自身的链接时的 SQL 查询【英文标题】:SQL query when a table has a link to itself 【发布时间】:2012-06-02 10:16:27 【问题描述】:你好,说我有一张桌子:
Person:
PersonId
Name
ManagerId
所以 ManagerId 是对另一个人的引用。
所以数据库中可能有一个人:
1
Bob
null
2
Steve
1
3
Tim
2
所以 Bob 是 Steve 的经理,Steve 是 Tim 的经理。
所以我想做的是编写一个查询,让 Bob 管理下的所有人。无论是直接的还是间接的。所以我想同时得到史蒂夫和蒂姆。在同一行。
如果我写:
select * from Person
where ManagerId = 1 I would get only Steve.
我该如何写才能让每个人都直接或间接地服从 Bob?
【问题讨论】:
什么数据库?不同的数据库对此任务使用不同的方法。 这是树形结构吗?就像 a)Bob 是 Steve 和 George 的经理(示例)。Steve 是 Anne 和 Nick 的经理。George 是 Stella 和 Bruce 的经理。乔治与安妮和尼克无关。史蒂夫与斯特拉和布鲁斯毫无关系。或者它是一个简单的链? Bob->Steve->Tim->Nick->Stella->等 【参考方案1】:您可以使用公用表表达式 (CTE) 来解决此问题。正如 Andrei 指出的那样,CTE 可用于递归(请参阅 Andrei 在他的帖子中包含的优秀参考资料)。假设您有一个如下表:
create table Person
(
PersonId int primary key,
Name varchar(25),
ManagerId int foreign Key references Person(PersonId)
)
让我们将以下数据插入到表中:
insert into Person (PersonId, Name, ManagerId) values
(1,'Bob', null),
(2, 'Steve',1),
(3, 'Tim', 2)
(4, 'John', 3),
(5, 'James', null),
(6, 'Joe', 5)
然后我们想要一个查询,该查询将返回直接或间接向 Bob 报告的每个人,即 Steve、Tim 和 John。我们不想返回 James 和 Bob,因为他们没有向任何人报告,或者 Joe,因为他向 James 报告。这可以通过 CTE 查询来完成,如下所示:
WITH Managers AS
(
--initialize
SELECT PersonId, Name, ManagerId
FROM Person WHERE ManagerId =1
UNION ALL
--recursion
SELECT p.PersonId, p.Name, p.ManagerId
FROM Person p INNER JOIN Managers m
ON p.ManagerId = m.PersonId
)
SELECT * FROM Managers
此查询返回正确的结果:
PersonId Name ManagerId
----------- ------------------------- -----------
2 Steve 1
3 Tim 2
4 John 3
编辑:假设 OP 使用 SQL Server 2005 或更高版本,此答案是有效的。我不知道这种语法在 mysql 或 Oracle 中是否有效。
【讨论】:
【参考方案2】:如果您使用的是 MS SQL Server 2005 或更高版本,则可以使用 CTE,正如 @AndreiDrynov 指出的那样,如下所示:
;WITH Emps(PersonId, Name, PersonLevel, ManagerName)
AS
(
SELECT PersonId, Name, 0 AS PersonLevel,
CONVERT(NVARCHAR(50), 'No Manager') AS ManagerName
FROM Persons
WHERE ManagerId IS NULL
Union All
SELECT p.PersonId, P.Name, e.PersonLevel + 1 , e.Name
FROM Persons p
INNER JOIN Emps e ON p.ManagerId = e.PersonId
)
SELECT *
FROM Emps
WHERE PersonLevel <= 2
此查询应为您提供以下信息:
PersonId | Name | Peroson Level | Manager
------------+---------+------------------+--------------
1 Bob 0 No Manager
2 Steve 1 Bob
3 Tim 2 Steve
您可以在这里看到它的实际效果:
DEMO
【讨论】:
【参考方案3】:select *
from Person A
inner join Person B ON B.PersonID = A.ManagerID
where ManagerId = 1
【讨论】:
以上是关于当表具有指向自身的链接时的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章