我想创建一个存储过程来查找谁是部门的老板。 所有经理都包含在带有前缀“_Head”的部门中。
我有两个采用这种结构的表并使用 SQL Server 2014。
SQL Server 表:
人
PersonID | DepartID | PersonName
---------+----------+----------------------
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
更新:
PersonID - PK
Person.DepartID = Depart.DepartID - FK
出发
DepartID | ParentID | DepartName
---------+----------+--------------
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
更新:
DepartID - PK
Depart.ParentID = Depart.DepartID - FK
Depart.DepartID = Person.DepartID - FK
“_Head of something”可以包含随机字符而没有以前的部门名称
例如:“_SubDep2 主管”可以是“_部门 XXX/YYY”
树视图:
ROOT [DepartID = 77, ParentID = NULL]
|- _Head of Root [DepartID = 110, ParentID = 77]
|- RootManager [PersonID = 138, DepartId = 110]
|- Dep1 [DepartID = 73, ParentID = 77]
|- _Head of Dep1 [DepartID = 90, ParentID = 73]
|- Manager1 [PersonID = 248, DepartId = 90]
|- User1 [PersonID = 63, DepartId = 73]
|- User2 [PersonID = 218, DepartId = 73]
|- Dep2 [DepartID = 98, ParentID = 77]
|- _Head of Dep2 [DepartID = 96, ParentID = 98]
|- Manager2 [PersonID = 216, DepartId = 96]
|- SubDep2 [DepartID = 23, ParentID = 98]
|- _Head of SubDep2 [DepartID = 93, ParentID = 23]
|- Manager3 [PersonID = 161, DepartId = 93]
|- Manager4 [PersonID = 222, DepartId = 93]
|- User3 [PersonID = 118, DepartId = 23]
|- User4 [PersonID = 160, DepartId = 23]
|- Dep3 [DepartID = 86, ParentID = 77]
|- User5 [PersonID = 259, DepartId = 86]
想要的结果:
我试过了:
带有 INNER JOIN 的 SQL 查询,但它仅适用于一级。
SQL 和 CTE,我合并了 Department 表,但我不能和 Person 表合并。
有人可以帮我解决这个话题吗?
非常感谢您的支持
答案 0 :(得分:0)
我建议您重新审视和规范您的数据库设计。在停机期间,如果这是一个正在使用的数据库,使用视图作为抽象来查询数据可以提供无缝更改,直到您重新访问模型。模型更新完成后,只需更新视图,所有使用该视图的应用程序都不需要更改。
对于您当前的设计,以下查询将有助于根据识别部门负责人的模式确定经理:
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
PersonId | PersonName -------: | :--------- 248 | Manager1<块引用>
exec sp_GetManager 'User2'
GO
PersonId | PersonName -------: | :--------- 248 | Manager1<块引用>
exec sp_GetManager 'Manager3'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager<块引用>
exec sp_GetManager 'User5'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager<块引用>
exec sp_GetManager 'User3'
GO
PersonId | PersonName -------: | :--------- 161 | Manager3 222 | Manager4<块引用>
exec sp_GetManager 'User4'
GO
PersonId | PersonName -------: | :--------- 161 | Manager3 222 | Manager4<块引用>
exec sp_GetManager 'Manager1'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager<块引用>
exec sp_GetManager 'Manager2'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager
db<>fiddle here
这似乎更乏味,但如果您打算使用初始递归方法遍历树,那么此尝试可能会指导您根据外键遍历层次结构
<块引用>select @@version;
GO
| (No column name) | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Microsoft SQL Server 2019 (RTM-CU6) (KB4563110) - 15.0.4053.23 (X64) <br> Jul 25 2020 11:26:55 <br> Copyright (C) 2019 Microsoft Corporation<br> Express Edition (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)<br> |<块引用>
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
PersonId | PersonName -------: | :--------- 248 | Manager1<块引用>
exec sp_GetManager 'User2'
GO
PersonId | PersonName -------: | :--------- 248 | Manager1<块引用>
exec sp_GetManager 'Manager3'
GO
PersonId | PersonName -------: | :--------- 216 | Manager2<块引用>
exec sp_GetManager 'User5'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager<块引用>
exec sp_GetManager 'User3'
GO
PersonId | PersonName -------: | :--------- 161 | Manager3 222 | Manager4<块引用>
exec sp_GetManager 'User4'
GO
PersonId | PersonName -------: | :--------- 161 | Manager3 222 | Manager4<块引用>
exec sp_GetManager 'Manager1'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager<块引用>
exec sp_GetManager 'Manager2'
GO
PersonId | PersonName -------: | :---------- 138 | RootManager
db<>fiddle here