我有一个SQL,它使用递归CTE扩展自我重组员工表,构建由用户和严重性级别聚合的缺陷结果集。
这是我的CTE:
ALTER FUNCTION [dbo].[fnGetEmployeeHierarchyByUsername]
(
@NTID varchar(100) = null
)
RETURNS TABLE
AS
RETURN
(
WITH yourcte AS
(
SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName--, Name
FROM Employees
WHERE NTID = @NTID
UNION ALL
SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName--, e.Name
FROM Employees e
JOIN yourcte y ON e.ManagerNTID = y.NTID
)
SELECT EmployeeId, ManagerID, NTID, FullName--, Name
FROM yourcte
)
这是我用于汇总用户缺陷的SQL:
SELECT e.FullName, Urgent, High, Medium, Low
FROM fnGetEmployeeHierarchyByUsername ('ssalvati') e
LEFT OUTER JOIN(
SELECT [AssignedTo],
SUM([1-Urgent]) AS Urgent,
SUM([2-High]) AS High,
SUM([3-Medium]) AS Medium,
SUM([4-Low]) AS Low
FROM (SELECT [AssignedTo],[BusinessSeverity] FROM Defects WHERE Status <> 'Closed') D
PIVOT (COUNT([BusinessSeverity]) FOR [BusinessSeverity] IN ([1-Urgent],[2-High],[3-Medium],[4-Low])) V
GROUP BY [AssignedTo]) AS def
ON e.ntid = def.[AssignedTo]
我希望有一个porc,它将用户名作为参数,并生成类似于上面的SQL的结果,但有2个增强功能:
我需要它列出作为param传入的用户,作为结果集的第一条记录。
我需要向经理报告的员工只显示一个级别,而不显示完整的树。第一级应该是分配给汇总到所有一级用户的人的所有潜在缺陷的汇总。换句话说,我不想像现在这样在经理下面显示一棵完整的树,我需要它只显示一个层次,但是所有层次都有一些缺陷。
想法?
答案 0 :(得分:1)
这个没有经过测试,因为我没有在这里安装mssql,也没有测试你的数据,但是,我认为这应该是正确的,至少会让你朝着有用的方向发展。
首先,您需要更改UDF中的查询以提供另外两条信息。聚合崩溃的“最顶层”员工(我认为您说的是第一个直接报告,而不是最优秀的员工),以及整体深度。就这样:
WITH yourcte AS
(
SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName, 0 as Depth, ntid as Topmost
FROM Employees
WHERE NTID = @NTID
UNION ALL
SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName, y.Depth+1, case when y.depth = 0 then e.ntid else y.Topmost end
FROM Employees e
JOIN yourcte y ON e.ManagerNTID = y.NTID
)
SELECT EmployeeId, ManagerID, NTID, FullName, Depth, Topmost
FROM yourcte
然后,您的实际查询需要一些额外的细节来提取该信息并使用它
SELECT
e.FullName,
Urgent,
High,
Medium,
Low
FROM fnGetEmployeeHierarchyByUsername ('ssalvati') e
LEFT OUTER JOIN(
SELECT [AssignedTo],
SUM([1-Urgent]) AS Urgent,
SUM([2-High]) AS High,
SUM([3-Medium]) AS Medium,
SUM([4-Low]) AS Low
FROM (SELECT [AssignedTo],[BusinessSeverity] FROM Defects WHERE Status <> 'Closed') D
join fnGetEmployeeHierarchyByUsername ('ssalvati') e2 on d.AssignedTo = e2.ntid
PIVOT (COUNT([BusinessSeverity]) FOR [BusinessSeverity] IN ([1-Urgent],[2-High],[3-Medium],[4-Low])) V
where e2.TopMost = e.ntid
GROUP BY [AssignedTo]) AS def
ON e.ntid = def.[AssignedTo]
where e.Depth <= 1
对UDF的双重调用可能有点贵,因此您可能需要考虑将其放入sproc并使用临时表来捕获要加入的UDF的结果。
另请注意,UDF可以采用额外的参数来确定“最顶层”的深度,使其更加通用,使其处于硬编码形式。
答案 1 :(得分:0)
如果您修改了您的cte以包含深度,即
WITH yourcte AS
(
SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName, 0 AS Depth
FROM Employees
WHERE NTID = @NTID
UNION ALL
SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName, y.Depth + 1
FROM Employees e
JOIN yourcte y ON e.ManagerNTID = y.NTID
)
然后您可以按深度排序输出(因为输入参数中的用户应该在深度为零)。使用此功能,您还应该能够限制返回的深度,并在深度> = 1
时聚合缺陷修改强>
使用上面添加的SQL,您基本上想要将所有缺陷汇总到1级用户?因此,此级别的用户的NTID成为所有深度为&gt; = 1的记录的逐项。对下面的cte的另一个编辑将NTID添加为GroupingID,您可以使用它来分组/ rollup < / p>
WITH yourcte AS
(
SELECT EmployeeId, ManagerNTID, ManagerID, NTID
,FullName, 0 AS Depth, NTID as GroupingID
FROM Employees
WHERE NTID = @NTID
UNION ALL
SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID
,e.FullName, y.Depth + 1, CASE
WHEN y.Depth + 1 = 1 THEN e.NTID
ELSE y.GroupingId
END
FROM Employees e
JOIN yourcte y ON e.ManagerNTID = y.NTID
)
答案 2 :(得分:0)
这是一种漫长的虚拟方式。我有它的工作,但解决方案可能会好得多。我希望有人会发布一个SQL2005方法来完成这个......
alter PROC sel_DefectReportByManagerNTID_rollup
(@ManagerNTID NVARCHAR(100))
AS
CREATE TABLE #DefectCounts
(
id INT IDENTITY(1, 1) ,
MgrRolledInto NVARCHAR(100) NULL,
AltBusinessSeverity NVARCHAR(100) NULL,
DefectCount INT NULL
);
CREATE TABLE #directReports
(
pk INT IDENTITY(1, 1) ,
directReportNTID NVARCHAR(100) NULL
);
INSERT INTO #directReports
SELECT NTID FROM Employees WHERE ManagerNTID = @ManagerNTID
--select * from #directReports
DECLARE @maxPK INT;
SELECT @maxPK = MAX(PK) FROM #directReports
DECLARE @pk INT;
SET @pk = 1
INSERT INTO #DefectCounts (MgrRolledInto,AltBusinessSeverity,DefectCount)
SELECT @ManagerNTID, d.AltBusinessSeverity, COUNT(*)
FROM Defects d
JOIN StatusCode C ON C.CodeName = d.Status AND c.scid = 10
WHERE d.AssignedTo = @ManagerNTID
GROUP BY d.AltBusinessSeverity
WHILE @pk <= @maxPK
BEGIN
/* Get one direct report at a time to aggregate their defects under them... */
DECLARE @dirRptNTID NVARCHAR(100);
SET @dirRptNTID = (SELECT directReportNTID
FROM #directReports
WHERE PK = @pk)
INSERT INTO #DefectCounts (MgrRolledInto,AltBusinessSeverity,DefectCount)
SELECT @dirRptNTID, d.AltBusinessSeverity, COUNT(*)
FROM Defects d
JOIN StatusCode C ON C.CodeName = d.Status AND c.scid = 10
JOIN (SELECT * FROM fnGetEmployeeHierarchyByUsername(@dirRptNTID) ) emp ON emp.NTID = d.AssignedTo
WHERE d.AssignedTo IS NOT NULL
GROUP BY d.AltBusinessSeverity
SELECT @pk = @pk + 1
END
SELECT e.FullName,
isnull(Urgent,0) as Urgent,
isnull(High,0) as High,
isnull(Medium,0) as Medium,
isnull(Medium3000,0) as Medium3000,
isnull(Low,0) as Low
FROM ( select * from fnGetEmployeeHierarchyByUsername (@ManagerNTID) where depth <= 1) e
left outer join (
SELECT MgrRolledInto,
SUM([1-Urgent]) AS Urgent,
SUM([2-High]) AS High,
SUM([3-Medium]) AS Medium,
SUM([3-Medium (3000)]) AS Medium3000,
SUM([4-Low]) AS Low
FROM #DefectCounts dfs
PIVOT
(sum(DefectCount) FOR AltBusinessSeverity IN ([1-Urgent],[2-High],[3-Medium],[3-Medium (3000)],[4-Low])) V
GROUP BY MgrRolledInto
) def_data on def_data.MgrRolledInto = e.NTID
order by e.depth