这是我创建的表格和一些初始值。
/*Make the table*/
CREATE TABLE PEOPLE(
ID int PRIMARY KEY,
NAME varchar(100) NOT NULL,
SUPERIOR_NAME varchar(100)
);
/*Give it some initial values*/
INSERT INTO PEOPLE VALUES(1, 'A',NULL), (2, 'B', 'E'), (3, 'C', 'A'),
(4, 'D', 'A'), (5, 'E',NULL), (6, 'F', 'D');
我需要编写一个SQL程序,它将返回一个人的所有下属,包括所有子下属等等。在这个例子中,如果我输入A,我应该得到C,D和F(D的下属,它是A的下属)作为输出。但我只能达到一个级别,即C和D.如何让它适用于层次结构中的任何级别?我看错了吗?
以下是我为一个级别编写的程序:
USE DB
GO
CREATE PROCEDURE SP_GETSUBS @NAME VARCHAR(100)
AS
BEGIN
IF @NAME IN (SELECT SUPERIOR_NAME FROM PEOPLE)
SELECT SUPERIOR_NAME AS "NAME", NAME AS "SUBORDINATE" FROM PEOPLE WHERE
SUPERIOR_NAME=@NAME;
END
我正在考虑将第一级结果推送到临时表并使用递归,但我不知道如何使一个过程逐一运行列的条目。有任何想法吗?我使用SQL Server Management Studio 2012。
答案 0 :(得分:1)
使用自引用公用表表达式并在您的选择中保留顶级经理(Boss):
WITH OrganisationChart (Id, [Name], [Level], superior_name, [Boss])
AS
(
SELECT
Id, [Name], 0 AS [Level], superior_name, name
FROM
dbo.people
WHERE
superior_name IS NULL
UNION ALL
SELECT
emp.Id,
emp.[Name],
[Level] + 1,
emp.superior_name,
[Boss]
FROM
dbo.people emp
INNER JOIN
OrganisationChart
ON
emp.superior_name = OrganisationChart.name
)
SELECT
*
FROM
OrganisationChart
WHERE
name != [Boss]
感谢Simon Ince撰写了他的文章Hierarchies WITH Common Table Expressions.
答案 1 :(得分:0)
试试这个
CREATE PROCEDURE USP_GETSUBS
(
@NAME VARCHAR(100)
) -- USP_GETSUBS 'A'
AS
BEGIN
IF EXISTS (SELECT SUPERIOR_NAME FROM PEOPLE WHERE Name=@NAME)
BEGIN
WITH Subordinates AS
(
SELECT p.ID, p.Name, p.SUPERIOR_NAME
FROM PEOPLE AS p
WHERE p.Name = @NAME
UNION ALL
SELECT p.ID, p.Name, p.SUPERIOR_NAME
FROM PEOPLE AS p
INNER JOIN Subordinates AS sub ON p.SUPERIOR_NAME = sub.Name
)
SELECT s.SUPERIOR_NAME AS "NAME",s.Name AS "SUBORDINATE"
FROM Subordinates AS s
WHERE s.SUPERIOR_NAME IS NOT NULL
END
END
<强> SQL FIDDLE DEMO 强>
答案 2 :(得分:0)
您应该在ID上链接优先名称而不是名称。这是肯定的。
您可以通过使用2个临时表和迭代来执行此操作而无需递归或CTE。我会假装您SuperiorID
代替Superior_Name
CREATE PROCEDURE SP_GETSUBS
@ID INT
AS
BEGIN
DECLARE @allsubs AS TABLE(ID INT)
DECLARE @subs AS TABLE(ID INT)
DECLARE @temp AS TABLE(ID INT)
--Get immediate subordinates of the ID passed in
INSERT INTO @subs(ID)
SELECT ID FROM PEOPLE WHERE SUPERIORID = @ID
WHILE EXISTS(SELECT * FROM @subs)
BEGIN
DELETE @temp
--copy the subordinate list
INSERT INTO @temp
SELECT (ID) FROM @subs
DELETE @subs
--get the subordinates' subordinates
INSERT INTO @subs (ID)
SELECT ID FROM PEOPLE WHERE SUPERIORID IN (
SELECT ID FROM @temp
)
--add the subordinates to the full list
INSERT INTO @allsubs (ID)
SELECT ID FROM @temp
END
--select IDs from the full list
SELECT * FROM PEOPLE WHERE ID IN (
SELECT ID FROM @allsubs
)
END
如果发生过多的递归,这不会引发问题 - 虽然这在SQLServer的更高版本中不是问题。