我不会在SQL中编写那么多代码,并且需要做一些相当棘手的累积计算来计算疲劳分数'对于轮班工作的员工,随着时间累积得分,但也根据他们在轮班之间休息了多少小时而向下调整。
对于相关表格中的每一行,我有一个开始时间和一个结束时间,然后我计算差异,使用一个函数来计算这些时间之间每小时的疲劳分数(函数总和这些并返回一个总天数),然后计算这个疲劳分数在几天内的累积总和,当该人有一个体面的休息时,将其向下调整相当大的百分比。
我有一个可行的Cursor方法,但我很想尝试CTE方法 - 不是因为我一定认为它会更快,而是因为我之前从未做过递归CTE而我认为它这将是一个很好的学习和可能更整洁的代码。
但是我对CTE做了些蠢事......因为在结果集中,我的测试对象每天都会获得越来越多的行数。即在第1天返回1行,第2天2,第3天3,等等。
这是我的Cursor方法,它运作得很好。 (它使用CTE构造游标操作的查询。)
DECLARE @EmployeeId AS NVARCHAR(8)
DECLARE @Actual_start AS DATETIME;
DECLARE @Actual_end AS DATETIME;
DECLARE @NextShift AS DATETIME;
DECLARE @HoursRest AS INT;
DECLARE @TotalWork_hrs AS INT;
DECLARE @Cumulative AS DECIMAL(5,2);
DECLARE @Cumulative_PREV AS DECIMAL(5,2);
DECLARE @DailyFatigue AS FLOAT;
DECLARE @FatigueDecay AS Decimal(3,2);
DECLARE @MyCursor AS CURSOR;
SET @Cumulative_PREV = 0;
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results;
CREATE TABLE #Results(
EmployeeID NVARCHAR(8)
, Actual_start DATETIME
, Actual_end DATETIME
, NextShift DATETIME
, HoursRest INT
, TotalWork_hrs INT
, DailyFatigue FLOAT
, FatigueDecay DECIMAL(3,2)
, Cumulative FLOAT
);
SET @MyCursor = CURSOR FOR
WITH CTE_1 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,LEAD([Actual_start]) OVER (PARTITION BY [EmployeeId] ORDER BY [EmployeeId], [Actual_start]) AS 'NextShift'
,[TotalWork_hrs]
,[Shift_Order]
FROM [HRBI].[dbo].[WFTM_Fatigue_Current]
WHERE
[Workday] = 'WD'
AND [Actual_start]> DATEADD(dd,-90,GETDATE())
AND [EmployeeId] = '00110838')
, CTE_2 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
, CONVERT(INT,COALESCE([NextShift],[Actual_end])-[Actual_end])*24 AS [HoursRest]
,[TotalWork_hrs]
,[Shift_Order]
FROM CTE_1)
, CTE_3 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
,[HoursRest]
,[TotalWork_hrs]
,[Shift_Order]
,dbo.ufn_GetDailyFatigue([Actual_start], [Actual_end]) AS [DailyFatigue]
, CASE
WHEN [HoursRest] > 16 THEN 1-POWER(0.50, ((HoursRest+8)/24-1) )
ELSE 0
END AS [FatigueDecay]
, ROW_NUMBER() OVER (ORDER BY [EmployeeId], [Actual_start]) AS ROW#
FROM CTE_2 )
SELECT [EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
,[HoursRest]
,[TotalWork_hrs]
,[DailyFatigue]
,[FatigueDecay]
FROM CTE_3
OPEN @MyCursor;
FETCH NEXT FROM @MyCursor INTO @EmployeeId, @Actual_start, @Actual_end, @NextShift, @HoursRest, @TotalWork_hrs, @DailyFatigue, @FatigueDecay;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Cumulative = @TotalWork_hrs + @Cumulative_PREV * (1-@FatigueDecay);
SET @Cumulative_PREV = @Cumulative;
INSERT INTO #Results ([EmployeeID], [Actual_start],[Actual_end], [NextShift], [HoursRest], [TotalWork_hrs], [DailyFatigue], [FatigueDecay], [Cumulative])
VALUES(@EmployeeId, @Actual_start, @Actual_end, @NextShift, @HoursRest, @TotalWork_hrs, @DailyFatigue, @FatigueDecay, @Cumulative)
FETCH NEXT FROM @MyCursor INTO @EmployeeId, @Actual_start, @Actual_end, @NextShift, @HoursRest, @TotalWork_hrs, @DailyFatigue, @FatigueDecay;
END
CLOSE @MyCursor;
DEALLOCATE @MyCursor;
SELECT * FROM #Results
ORDER BY EmployeeID, Actual_start
它完全返回我想要的东西。请注意突出显示:这是一个例子,当工作人员在前一班次与此班次之间有一个不错的休息时间,因此他们的累积分数已经调低。
这是我使用递归CTE的尝试,只是因为它只是在其他CTE的末尾增加了一个CTE,并且没有任何现在多余的CURSOR东西:< / p>
WITH CTE_1 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,LEAD([Actual_start]) OVER (PARTITION BY [EmployeeId] ORDER BY [EmployeeId], [Actual_start]) AS 'NextShift'
,[TotalWork_hrs]
,[Shift_Order]
, ROW_NUMBER() OVER (PARTITION BY [EmployeeId] ORDER BY [EmployeeId], [Actual_start]) AS ROW#
FROM [HRBI].[dbo].[WFTM_Fatigue_Current]
WHERE
[Workday] = 'WD'
AND [Actual_start]> DATEADD(dd,-3,GETDATE())
AND [EmployeeId] = '00110838')
, CTE_2 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
,[TotalWork_hrs]
,[Shift_Order]
,[ROW#]
, CONVERT(INT,COALESCE([NextShift],[Actual_end])-[Actual_end])*24 AS [HoursRest]
FROM CTE_1)
, CTE_3 AS
(SELECT
[EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
,[TotalWork_hrs]
,[Shift_Order]
,[ROW#]
,[HoursRest]
,dbo.ufn_GetDailyFatigue([Actual_start], [Actual_end]) AS [Fatigue]
, CASE
WHEN [HoursRest] > 16 THEN 1-POWER(0.50, ((HoursRest+8)/24-1) )
ELSE 0
END AS [FatigueDecay]
FROM CTE_2 ),
CTE_4 AS
(SELECT [EmployeeId]
,[Actual_start]
,[Actual_end]
,[NextShift]
,[TotalWork_hrs]
,[Shift_Order]
,[ROW#]
,[HoursRest]
,[Fatigue]
,[FatigueDecay]
,[Cumulative] = [Fatigue]
FROM CTE_3
UNION ALL
SELECT
new.[EmployeeId]
,new.[Actual_start]
,new.[Actual_end]
,new.[NextShift]
,new.[TotalWork_hrs]
,new.[Shift_Order]
,new.[ROW#]
,new.[HoursRest]
,new.[Fatigue]
,new.[FatigueDecay]
,[Cumulative] = new.[Fatigue] + base.Cumulative*new.FatigueDecay
FROM CTE_3 new
INNER JOIN CTE_4 base
ON base.EmployeeId = new.EmployeeId
AND new.ROW# = base.ROW# + 1
)
SELECT * FROM CTE_4
ORDER BY Actual_start
OPTION (MAXRECURSION 0)
...并且根据下面的屏幕截图,我在那里有一个ROW#列,显示返回的行数因某些原因而不断增加,而且我的累计计算没有工作
有人可以找到我在这里出错的地方吗?
答案 0 :(得分:1)