我有一个看起来像这样的StaffLookup表。
UserSrn | UserName | ManagerSrn
===============================
ABC1 | Jerome | NULL
ABC2 | Joe | ABC1
ABC3 | Paul | ABC2
ABC4 | Jack | ABC3
ABC5 | Daniel | ABC3
ABC6 | David | ABC2
ABC7 | Ian | ABC6
ABC8 | Helen | ABC6
员工结构如下所示。
|- Jerome
|
|- Joe
||
||- Paul
|||
|||- Jack
|||
|||- Daniel
||
||- David
|||
|||- Ian
|||
|||- Helen
我有一个SurveyResponses列表,看起来像这样。
UserSrn | QuestionId | ResponseScore
====================================
ABC2 | 1 | 5
ABC2 | 3 | 4
ABC4 | 16 | 3
...
我想要做的事情听起来很简单,但我很难找到一个简洁,快捷的方法。我想创建一个带有Srn的sproc并返回结构中该Srn下的所有工作人员。
如果QuestionId为16,则表示已完成调查。我想为Srn进入(最高管理者)返回一行,其中包含该经理下直接下属的已完成调查。根据这一点,我希望原管理人员下的每位经理都能为他们的每份直接下属等完成调查。
当我将高级经理设为Joe(ABC2)时,我希望看到下面的数据。
UserName | Completed | Total
============================
Joe | 2 | 2
Paul | 1 | 2
David | 0 | 2
TOTAL | 3 | 6
答案 0 :(得分:2)
我相信这是有效的,基于所提供的信息。将@mgrSrn
作为输入参数将其转换为SP应该不会太困难。
declare @users table
(UserSrn char(4)
,UserName varchar(6)
,ManagerSrn char(4)
)
INSERT @users
SELECT 'ABC1','Jerome',NULL
UNION SELECT 'ABC2','Joe','ABC1'
UNION SELECT 'ABC3','Paul','ABC2'
UNION SELECT 'ABC4','Jack','ABC3'
UNION SELECT 'ABC5','Daniel','ABC3'
UNION SELECT 'ABC6','David','ABC2'
UNION SELECT 'ABC7','Ian','ABC6'
UNION SELECT 'ABC8','Helen','ABC6'
declare @results table
(UserSrn char(4)
,QuestionId tinyint
,ResponseScore tinyint
)
INSERT @results
SELECT 'ABC2',1,1
UNION SELECT 'ABC4',16,1
declare @mgrSrn char(4)
set @mgrSrn = 'ABC2' -- Joe
;WITH completedCTE
AS
(
SELECT c.*
,CASE WHEN r.UserSrn IS NOT NULL
THEN 1
ELSE 0
END AS completeCount
,1 AS totalCount
FROM @users as c
LEFT JOIN @results AS r
ON r.UserSrn = c.UserSrn
AND r.QuestionId = 16
)
,recCTE
AS
(
SELECT UserSrn
,UserName
,CAST(NULL AS CHAR(4)) AS ManagerSrn
,1 as level
,completeCount
,totalCount
FROM completedCTE
WHERE UserSrn = @mgrSrn
UNION ALL
SELECT t.UserSrn
,t.UserName
,t.ManagerSrn
,c.level + 1 AS level
,t.completeCount AS completeCount
,t.totalCount AS totalCount
FROM completedCTE AS t
JOIN recCTE AS c
ON c.UserSrn = t.ManagerSrn
)
,resultCTE
AS
(
SELECT r.ManagerSrn
,t.UserName
,r.level
,SUM(completeCount) completeCount
,SUM(totalCount) totalCount
FROM recCTE AS r
JOIN @users AS t
ON t.UserSrn = r.ManagerSrn
WHERE r.ManagerSrn IS NOT NULL
GROUP BY r.ManagerSrn
,t.UserName
,r.level
)
SELECT UserName
,completeCount
,totalCount
FROM resultCTE
ORDER BY level
,UserName
OPTION (MAXRECURSION 0)
答案 1 :(得分:2)
试试这个:
DECLARE @Staff table (UserSrn char(4), UserName varchar(10), ManagerSrn char(4))
INSERT @Staff VALUES ('ABC1','Jerome', NULL )
INSERT @Staff VALUES ('ABC2','Joe' ,'ABC1')
INSERT @Staff VALUES ('ABC3','Paul' ,'ABC2')
INSERT @Staff VALUES ('ABC4','Jack' ,'ABC3')
INSERT @Staff VALUES ('ABC5','Daniel','ABC3')
INSERT @Staff VALUES ('ABC6','David' ,'ABC2')
INSERT @Staff VALUES ('ABC7','Ian' ,'ABC6')
INSERT @Staff VALUES ('ABC8','Helen' ,'ABC6')
DECLARE @SurveyResponses table (UserSrn char(4), QuestionId int, ResponseScore int)
INSERT @SurveyResponses VALUES ('ABC2',1 ,5)
INSERT @SurveyResponses VALUES ('ABC2',3 ,4)
INSERT @SurveyResponses VALUES ('ABC6',16,3)
DECLARE @RootUserSrn char(4)
SET @RootUserSrn='ABC2'
--get tree of given user
;WITH StaffTree AS
(
SELECT
UserSrn, UserName, ManagerSrn, UserSrn AS ManagerUserSrn, UserName AS ManagerUserName, 1 AS LevelOf
FROM @Staff
WHERE UserSrn=@RootUserSrn
UNION ALL
SELECT
s.UserSrn, s.UserName, s.ManagerSrn, t.UserSrn, t.UserName, t.LevelOf+1
FROM StaffTree t
INNER JOIN @Staff s ON t.UserSrn=s.ManagerSrn
WHERE s.ManagerSrn=@RootUserSrn
)
SELECT
s.UserName,COUNT(r.QuestionId) AS Completed,'???' as total
FROM StaffTree s
LEFT OUTER JOIN @SurveyResponses r ON s.UserSrn=r.UserSrn
GROUP BY s.UserName,s.LevelOf
ORDER BY s.LevelOf
输出:
UserName Completed total
---------- ----------- -----
Joe 2 ???
David 1 ???
Paul 0 ???
OP评论后编辑:
DECLARE @Staff table (UserSrn char(4), UserName varchar(10), ManagerSrn char(4))
INSERT @Staff VALUES ('ABC1','Jerome', NULL )
INSERT @Staff VALUES ('ABC2','Joe' ,'ABC1')
INSERT @Staff VALUES ('ABC3','Paul' ,'ABC2')
INSERT @Staff VALUES ('ABC4','Jack' ,'ABC3')
INSERT @Staff VALUES ('ABC5','Daniel','ABC3')
INSERT @Staff VALUES ('ABC6','David' ,'ABC2')
INSERT @Staff VALUES ('ABC7','Ian' ,'ABC6')
INSERT @Staff VALUES ('ABC8','Helen' ,'ABC6')
DECLARE @SurveyResponses table (UserSrn char(4), QuestionId int, ResponseScore int)
INSERT @SurveyResponses VALUES ('ABC2',1 ,5)
INSERT @SurveyResponses VALUES ('ABC2',3 ,4)
INSERT @SurveyResponses VALUES ('ABC6',16,3)
DECLARE @RootUserSrn char(4)
SET @RootUserSrn='ABC2'
--get tree of given user
;WITH StaffTree AS
(
SELECT
UserSrn, UserName, ManagerSrn, UserSrn AS ManagerUserSrn, UserName AS ManagerUserName, 1 AS LevelOf
FROM @Staff
WHERE UserSrn=@RootUserSrn
UNION ALL
SELECT
s.UserSrn, s.UserName, s.ManagerSrn, t.UserSrn, t.UserName, t.LevelOf+1
FROM StaffTree t
INNER JOIN @Staff s ON t.UserSrn=s.ManagerSrn
WHERE s.ManagerSrn=@RootUserSrn
)
, MINLevel AS (
SELECT MIN(LevelOf) AS MinLevelOf FROM StaffTree
)
, TotalLevel AS (
SELECT
SUM(CASE WHEN s.LevelOf !=m.MinLevelOf THEN 1 ELSE 0 END) AS TotalOf
FROM StaffTree s
CROSS JOIN MINLevel m
)
,Results AS (
SELECT
s.UserName,SUM(CASE WHEN r.QuestionId=16 THEN 1 ELSE 0 END) AS Completed,t.TotalOf as total,s.LevelOf
FROM StaffTree s
LEFT OUTER JOIN @SurveyResponses r ON s.UserSrn=r.UserSrn
CROSS JOIN TotalLevel t
GROUP BY s.UserName,s.LevelOf,t.TotalOf
)
SELECT
UserName,Completed,total, 1,LevelOf
FROM Results
UNION ALL
SELECT
'TOTAL',SUM(Completed),SUM(total),2,0
FROM Results
ORDER BY 4,5
输出:
UserName Completed total LevelOf
---------- ----------- ----------- ----------- -----------
Joe 0 2 1 1
David 1 2 1 2
Paul 0 2 1 2
TOTAL 1 6 2 0
(4 row(s) affected)
我仍然无法看到给定数据如何导致Joe完成= 2而Paul已完成1.我将给定数据从('ABC4',16,3)
更改为('ABC6',16,3)
所以结果集中有人会有一个完成。
答案 2 :(得分:1)
编辑:我使用SQL Server 2008生成INSERT语句......
我可以生成您的层次结构,但不能生成结果。抱歉,样本输入和输出数据没有占用,
您需要LevelNum来处理最有可能出现在层次结构中的结果
DECLARE @staff TABLE (UserSrn char(4), UserName varchar(10), ManagerSrn char(4))
INSERT @staff (UserSrn, UserName, ManagerSrn)
VALUES
('ABC1' , 'Jerome' , NULL),('ABC2' , 'Joe' , 'ABC1'),
('ABC3' , 'Paul' , 'ABC2'),('ABC4' , 'Jack' , 'ABC3'),
('ABC5' , 'Daniel' , 'ABC3'),('ABC6' , 'David' , 'ABC2'),
('ABC7' , 'Ian' , 'ABC6'),('ABC8' , 'Helen' , 'ABC6')
DECLARE @results TABLE (UserSrn char(4), QuestionId varchar(10), ResponseScore char(4))
INSERT @results (UserSrn, QuestionId, ResponseScore)
VALUES ('ABC2' , 2 , 5),('ABC2' , 3 , 4),('ABC4' , 16 , 3)
;WITH cHierarchy AS
(
SELECT
s.UserSrn, S.UserName, S.ManagerSrn, CAST('|' AS varchar(50)) AS LevelStr, 0 AS LevelNum
FROM
@staff S
WHERE
S.ManagerSrn IS NULL
UNION ALL
SELECT
s.UserSrn, S.UserName, S.ManagerSrn, CAST(Level + '|' AS varchar(50)), LevelNum + 1
FROM
cHierarchy C JOIN @staff S ON C.UserSrn = S.ManagerSrn
)
SELECT
*
FROM
cHierarchy C