0

我正在实施一个用于监控性能的积分跟踪系统。员工的目标是获得尽可能少的分数。有一个积分系统,允许员工通过在不同时期表现更好来减少他们的积分。表现30天最多扣1分,60天无事故扣2分,90天无事故扣4分。它们不能累积负值,并且积分从最旧的日期滚动到最新的日期。下面的示例表表示已导入 SQL Server 2012 数据库的现有表。

Employee    Points    Date  Previous    Note
Smith, Joe  0.25    3/21/2013       
Smith, Joe  1       4/1/2013        
Smith, Joe  0.25    5/6/2013        
Smith, Joe  0.5     5/8/2013        
Smith, Joe  1       7/10/2013       
Jones, Tom  1       4/10/2013       
Jones, Tom  1       4/18/2013       
Jones, Tom  0.5     4/22/2013       
Jones, Tom  2       6/25/2013       
Jones, Tom  0.25    7/26/2013       
Jones, Tom  0.25    7/28/2013       

由于数据的动态使用,转至 C#、Excel、Email 等多个来源,因此需要构建确定性函数并生成更新后的表或视图,以显示类似于以下内容的内容。下面的示例将与报告在 2013 年 5 月 18 日提取时的样子相同。每个员工将被扣除 1 分。因为 Joe 的第一个点是 0.25,它将被设置为 0,而下一个点 1.00 将减去剩余的 0.75 到 0.25 的值。因为汤姆的第一分是满分,所以会从 1 分中减去,导致该日期为 0 分。该函数还应在更新点值之前记录点列的先前值。该函数应提供关于更改点的原因的注释,日期在注释字段中会很好,但是 NoteDate 的单独列可以包含日期。该函数可以在 INSERT/UPDATE 触发器上运行,因为日常使用量非常低。它应该检查当前日期和最后一个日期。

Employee    Points  Date    Previous    Note
Smith, Joe  0.00    3/21/2013   0.25    Rolled Off by System - 30 Day Policy 05/01/2013
Smith, Joe  0.25    4/1/2013    1.00    Rolled Off by System - 30 Day Policy 05/01/2013
Smith, Joe  0.25    5/6/2013        
Smith, Joe  0.50    5/8/2013        
Jones, Tom  0.00    4/10/2013   1.00    Rolled Off by System - 30 Day Policy 05/22/2013
Jones, Tom  1.00    4/18/2013       
Jones, Tom  0.50    4/22/2013       

截至今天 2013 年 8 月 24 日,结果应反映以下内容。乔总得 0 分,汤姆总得 2 分,到 28 日将只得 1 分。大约有 2,000 条记录,因此很难手动更改这些记录。根据该系统的性质及其实施,可以运行 1 个脚本来协调当前记录,并有一个单独的脚本来管理正在进行的条目。

Employee    Points  Date    Previous    Note
Smith, Joe  0.00    3/21/2013   0.25    Rolled Off by System - 30 Day Policy 05/01/2013
Smith, Joe  0.00    4/1/2013    0.25    Rolled Off by System - 30 Day Policy 06/07/2013
Smith, Joe  0.00    5/6/2013    0.25    Rolled Off by System - 30 Day Policy 06/07/2013
Smith, Joe  0.00    5/8/2013    0.50    Rolled Off by System - 30 Day Policy 06/07/2013
Smith, Joe  0.00    7/10/2013   1.00    Rolled Off by System - 30 Day Policy 08/10/2013
Jones, Tom  0.00    4/10/2013   1.00    Rolled Off by System - 30 Day Policy 05/22/2013
Jones, Tom  0.00    4/18/2013   1.00    Rolled Off by System - 60 Day Policy 06/21/2013
Jones, Tom  0.00    4/22/2013   0.50    Rolled Off by System - 30 Day Policy 07/25/2013
Jones, Tom  1.50    6/25/2013   2.00    Rolled Off by System - 30 Day Policy 07/25/2013
Jones, Tom  0.25    7/26/2013       
Jones, Tom  0.25    7/28/2013       

我开始在 EmployeePerformance TABLE 上使用以下内容,以创建一个视图,以按其 ID 显示每个员工的每条记录之间的天数。然后我使用 DENSE_RANK() 用出勤视图中的所有信息对每个员工进行编号。我最初的想法是使用递增的 VARIABLE 循环遍历每个员工的 WHILE 循环,然后检查 DATE_DIFFERENCE 以查看是否有任何大于 30 的值。如果没有,我计划将该员工的所有记录插入到最终表中,并将它们从 Attend2 表中删除。比我认为需要的脚本要多得多。我改为考虑使用 CURSOR 创建一次性传递,然后再协调另一个函数。不过,我对 CURSOR 的经验很少。

CREATE VIEW Attendance AS
SELECT A.ID, A.FullName, A.EmployeeID, A.AttendanceDate, A.OccurrenceAmount, A.Comments, A.RecordCreatedDate, A.RecordCreatedUser, (DATEDIFF(DAY, A.AttendanceDate, B.AttendanceDate))*-1 AS DATE_DIFFERENCE
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY AttendanceDate) AS Row_Num, * 
FROM dbo.EmployeePerformance) AS A
LEFT JOIN (
SELECT ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY AttendanceDate) AS Row_Num, * 
FROM dbo.EmployeePerformance) AS B
ON A.EmployeeID=B.EmployeeID AND A.Row_Num=B.Row_Num+1  


SELECT *, DENSE_RANK() OVER (ORDER BY Attendance.EmployeeID) AS Row_Num
INTO dbo.Attend2
FROM dbo.Attendance

我有一些想法可以解决这个问题,但我希望有人可能遇到过类似的情况或以前遇到过类似的问题。我宁愿将它构建成一段我可以触发的简洁代码,并且在低容量环境中使用 SQL 数据库,我并不十分担心性能,但我想找到一个很好的解决方案,同时保持性能头脑。感谢您提供的任何帮助或反馈。

4

1 回答 1

1

我不确定我是否完全遵循您的方法/期望的结果,但对于初学者来说,您可以使用LEAD而不是JOIN/ROW_NUMBER()来获得DATEDIFF

SELECT ID
     , FullName
     , EmployeeID
     , AttendanceDate
     , OccurrenceAmount
     , Comments
     , RecordCreatedDate
     , RecordCreatedUser
     , DATEDIFF(DAY, AttendanceDate, LEAD(AttendanceDate) OVER(PARTITION BY EmployeeID ORDER BY AttendanceDate))*-1 AS DATE_DIFFERENCE
FROM dbo.EmployeePerformance) 
于 2013-08-25T04:23:05.513 回答