我建议重新审视和规范您的数据库设计。在停机期间,如果这是一个正在使用的数据库,使用视图作为抽象来查询数据可以提供无缝更改,直到您重新访问模型。模型更新完成后,只需更新视图,所有使用该视图的应用程序都不需要更改。
对于您当前的设计,以下查询将有助于根据识别部门负责人的模式确定经理:
方法 1 [推荐]
CREATE TABLE Person (
PersonID INTEGER,
DepartID INTEGER,
PersonName VARCHAR(11)
);
INSERT INTO Person
(PersonID, DepartID, PersonName)
VALUES
('138', '110', 'RootManager'),
('248', '90', 'Manager1'),
('63', '73', 'User1'),
('218', '73', 'User2'),
('216', '96', 'Manager2'),
('161', '93', 'Manager3'),
('222', '93', 'Manager4'),
('118', '23', 'User3'),
('160', '23', 'User4'),
('259', '86', 'User5');
CREATE TABLE Depart (
DepartID INTEGER,
ParentID VARCHAR(4),
DepartName VARCHAR(16)
);
INSERT INTO Depart
(DepartID, ParentID, DepartName)
VALUES
('77', NULL, NULL),
('100', '77', '_Head of Root'),
('73', '77', 'Dep1'),
('90', '73', '_Head of Dep1'),
('98', '77', 'Dep2'),
('96', '98', '_Head of Dep2'),
('23', '98', 'SubDep2'),
('93', '23', '_Head of SubDep2'),
('86', '77', 'Dep3');
GO
19 行受影响
DROP PROCEDURE IF EXISTS sp_GetManager
GO
✓
CREATE PROC sp_GetManager (@Name VARCHAR(20))
AS
BEGIN
DECLARE @ManagerResult TABLE(PersonId INTEGER, PersonName VARCHAR(20));
INSERT INTO @ManagerResult
SELECT
p.PersonId,
p.PersonName
FROM
Person p
WHERE p.DepartId in (
SELECT d.DepartId from Depart d
WHERE d.DepartName IN (
SELECT CONCAT('_Head of ',d1.DepartName) FROM
Depart d1
INNER JOIN Person p1 on p1.DepartId = d1.DepartId
WHERE p1.PersonName = @Name
)
)
IF EXISTS(
Select PersonId from @ManagerResult
)
SELECT * from @ManagerResult
ELSE
SELECT p.PersonId, p.PersonName FROM Person p where p.PersonName='RootManager'
END
GO
✓
exec sp_GetManager 'User1'
GO
个人身份 |人名
--------: | :---------
248 |经理1
exec sp_GetManager 'User2'
GO
个人身份 |人名
--------: | :---------
248 |经理1
exec sp_GetManager 'Manager3'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
exec sp_GetManager 'User5'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
exec sp_GetManager 'User3'
GO
个人身份 |人名
--------: | :---------
161 |经理3
222 |经理4
exec sp_GetManager 'User4'
GO
个人身份 |人名
--------: | :---------
161 |经理3
222 |经理4
exec sp_GetManager 'Manager1'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
exec sp_GetManager 'Manager2'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
db小提琴here
方法2
这似乎更乏味,但如果您打算使用初始递归方法遍历树,那么此尝试可能会引导您根据外键遍历层次结构
select @@version;
GO
| (无列名) |
| :------------------------------------------------ -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ---------------- |
| Microsoft SQL Server 2019 (RTM-CU6) (KB4563110) - 15.0.4053.23 (X64)
2020 年 7 月 25 日 11:26:55
版权所有 (C) 2019 Microsoft Corporation
Express Edition(64 位)在 Windows Server 2019 Standard 10.0 (内部版本 17763:)(管理程序)
|
CREATE TABLE Person (
PersonID INTEGER,
DepartID INTEGER,
PersonName VARCHAR(11)
);
INSERT INTO Person
(PersonID, DepartID, PersonName)
VALUES
('138', '110', 'RootManager'),
('248', '90', 'Manager1'),
('63', '73', 'User1'),
('218', '73', 'User2'),
('216', '96', 'Manager2'),
('161', '93', 'Manager3'),
('222', '93', 'Manager4'),
('118', '23', 'User3'),
('160', '23', 'User4'),
('259', '86', 'User5');
CREATE TABLE Depart (
DepartID INTEGER,
ParentID VARCHAR(4),
DepartName VARCHAR(16)
);
INSERT INTO Depart
(DepartID, ParentID, DepartName)
VALUES
('77', NULL, NULL),
('100', '77', '_Head of Root'),
('73', '77', 'Dep1'),
('90', '73', '_Head of Dep1'),
('98', '77', 'Dep2'),
('96', '98', '_Head of Dep2'),
('23', '98', 'SubDep2'),
('93', '23', '_Head of SubDep2'),
('86', '77', 'Dep3');
GO
19 行受影响
DROP PROCEDURE IF EXISTS sp_GetManager
GO
✓
CREATE PROC sp_GetManager(@Name VARCHAR(20))
AS
BEGIN
DECLARE @ManagerResult TABLE(PersonId INTEGER, PersonName VARCHAR(20), ManagementLevel INTEGER);
DECLARE @PersonId INTEGER, @PersonDepartmentId INTEGER;
SELECT @PersonId = p.PersonId , @PersonDepartmentId = p.DepartId FROM Person p
WHERE p.PersonName = @Name;
WITH
head_of_department AS (
SELECT d.DepartId, d.ParentId, d.DepartName, 0 as Level
FROM Depart d WHERE d.DepartId = @PersonDepartmentId
UNION ALL
SELECT d.DepartId, d.ParentId, d.DepartName, Level+1 as Level
FROM Depart d
INNER JOIN head_of_department hod on d.DepartId = hod.ParentId
WHERE d.ParentId is NOT NULL
),
including_sub_department AS (
SELECT DISTINCT * FROM (
SELECT * from head_of_department
UNION ALL
SELECT d.DepartId, d.ParentId, d.DepartName, hod.Level
FROM Depart d
INNER JOIN head_of_department hod on hod.DepartId = d.ParentId
) t WHERE t.DepartName LIKE '_Head of%'
)
INSERT INTO @ManagerResult
select p.PersonId, p.PersonName ,d.Level
from including_sub_department d
INNER JOIN Person p on d.DepartId = p.DepartId
WHERE
d.DepartId <> @PersonDepartmentId;
DECLARE @MinManagementLevel INTEGER;
IF EXISTS(
Select PersonId from @ManagerResult
)
BEGIN
SELECT @MinManagementLevel=MIN(ManagementLevel) FROM @ManagerResult;
SELECT PersonId, PersonName from @ManagerResult WHERE ManagementLevel = @MinManagementLevel;
END
ELSE
SELECT p.PersonId, p.PersonName FROM Person p where p.PersonName='RootManager'
END
GO
✓
exec sp_GetManager 'User1'
GO
个人身份 |人名
--------: | :---------
248 |经理1
exec sp_GetManager 'User2'
GO
个人身份 |人名
--------: | :---------
248 |经理1
exec sp_GetManager 'Manager3'
GO
个人身份 |人名
--------: | :---------
216 |经理2
exec sp_GetManager 'User5'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
exec sp_GetManager 'User3'
GO
个人身份 |人名
--------: | :---------
161 |经理3
222 |经理4
exec sp_GetManager 'User4'
GO
个人身份 |人名
--------: | :---------
161 |经理3
222 |经理4
exec sp_GetManager 'Manager1'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
exec sp_GetManager 'Manager2'
GO
个人身份 |人名
--------: | :----------
138 |根管理器
db小提琴here