[英]SQL Deduct value in one table from balance in another over multiple rows
I have a job that runs once per day against two tables, one containing an employees current holiday and PTO balances (dbo.Balance) and another containing new absences (dbo.Absence).我有一份每天针对两张表运行一次的工作,一张包含员工当前的假期和 PTO 余额 (dbo.Balance),另一张包含新的缺勤 (dbo.Absence)。 All values are in minutes.
所有值都以分钟为单位。
I'm trying to use logic to determine how much time each absence (previous day) should be applied to holiday, pto, or unpaid.我正在尝试使用逻辑来确定每次缺勤(前一天)应该应用于假期、取力器或无薪的时间。 It should apply in the following order: 1) Holiday, 2) PTO, 3) Unpaid.
它应该按以下顺序申请:1)假期,2)PTO,3)未付。 I was fine with the below code until an employee took two separate absences on the same day.
我对下面的代码很好,直到一名员工在同一天两次单独缺勤。 I've been beating my head on this for a week and can't figure out how to get it to basically have a running balance for each bucket at run time.
我已经为此苦苦挣扎了一周,无法弄清楚如何让它在运行时基本上对每个存储桶保持运行平衡。
The actual job is more complex and involves modifying start and end times for each record based on this output - so I do need a separate line for each absence record.实际的工作更复杂,涉及根据此 output 修改每条记录的开始和结束时间 - 所以我确实需要为每条缺勤记录单独一行。
dbo.Balance dbo.余额
| EmpId | HolidayBal | PTOBal |
|:------|:----------:|-------:|
| 1 | 60 | 120 |
| 2 | 240 | 600 |
| 3 | 0 | 0 |
dbo.Absence dbo.缺席
| EmpId | Time Taken |
|:------|-----------:|
| 1 | 210 |
| 1 | 45 |
| 2 | 120 |
| 3 | 120 |
What I would like the result to look like:我希望结果看起来像什么:
| EmpId | TimeTaken | HolidayUsed | PTOUsed | Unpaid |
|:------|:----------:|:-----------:|:-------:|:------:|
| 1 | 210 | 60 | 120 | 30 |
| 1 | 45 | 0 | 0 | 45 |
| 2 | 120 | 120 | 0 | 0 |
| 3 | 120 | 0 | 0 | 120 |
This is the code I have so far, just doesn't apply correctly when there is more than 1 absence in a day.这是我到目前为止的代码,只是在一天中有超过 1 次缺勤时无法正确应用。
SELECT
BAL.EmpId
,BAL.HolidayBalance
,BAL.PTOBalance
,AB.TimeTaken
,CASE --HOLIDAY CALCULATION
WHEN BAL.HolidayBalance - AB.TimeTaken >= 0 THEN -- HOLIDAY BALANCE EXCEEDS TIME USED, ALL TIME USED AS HOLIDAY
AB.TimeTaken
WHEN BAL.HolidayBalance > 0 AND BAL.HolidayBalance - AB.TimeTaken < 0 THEN -- TIME USED EXCEEDS HOLIDAY BALANCE, ALL HOLIDAY BALANCE USED
BAL.HolidayBalance
ELSE
0
END AS HolidayUsed
,CASE -- PTO CALCULATION
WHEN BAL.HolidayBalance - AB.TimeTaken >= 0 THEN -- ALL TIME USED AS HOLIDAY
0
WHEN BAL.HolidayBalance > 0 AND BAL.HolidayBalance - AB.TimeTaken < 0 THEN -- HOLIDAY BALANCE WAS LESS THAN TIME USED, HAVE A REMAINDER
CASE
WHEN ((BAL.PTOBalance) - (AB.TimeTaken - BAL.HolidayBalance)) >= 0 THEN -- HAVE ENOUGH PTO BALANCE TO COVER REMAINDER
((BAL.PTOBalance) - (AB.TimeTaken - BAL.HolidayBalance))
WHEN BAL.PTOBalance > 0 AND ((BAL.PTOBalance) - (AB.TimeTaken - BAL.HolidayBalance)) < 0 THEN -- HAVE A PTO BALANCE BUT DOES NOT COVER REMAINDER
BAL.PTOBalance
ELSE
0
END
WHEN BAL.PTOBalance > 0 AND BAL.HolidayBalance = 0 AND BAL.PTOBalance - AB.TimeTaken >=0 THEN -- HAVE PTO TO COVER IT AND NO HOLIDAY BALLANCE.
AB.TimeTaken
WHEN BAL.PTOBalance > 0 AND BAL.HolidayBalance = 0 AND AB.TimeTaken > BAL.PTOBalance THEN-- HAVE NO HOLIDAY AND PTO BALANCE DOES NOT COVER EVERYTHING
BAL.PTOBalance
ELSE 0
END AS PTOUsed
,CASE -- UNPAID CALCULATION
WHEN BAL.PTOBalance + BAL.HolidayBalance - AB.TimeTaken < 0 THEN --NOT ENOUGH PTO OR HOLIDAY TO COVER ABSENCE
AB.TimeTaken - (BAL.PTOBalance + BAL.HolidayBalance)
ELSE
0
END AS Unpaid
FROM dbo.Balance BAL
INNER JOIN dbo.Absence AB ON BAL.EmpId = AB.EmpId
Thanks for y'alls input.谢谢大家的投入。 I finally figured it out.
我终于弄明白了。 Had to basically add a running sum of the absence value (AbsenceSum) and then some tricky calculations to get everything to balance correctly.
基本上必须添加缺席值(AbsenceSum)的运行总和,然后进行一些棘手的计算以使所有内容正确平衡。 Wanted to post my solution should someone else have something similar!
如果其他人有类似的东西,想发布我的解决方案!
SELECT
EmpId
,TimeTaken
,StartTime
,HolidayUsed
,PTOUsed
,CASE
WHEN TimeTaken - (HolidayUsed + PTOUsed) > 0 THEN -- HAVE A BALANCE NEEDING UNPAID
TimeTaken - (HolidayUsed + PTOUsed)
ELSE
0
END AS Unpaid
FROM (
SELECT
AB.EmpId
,TimeTaken
,AB.AbsenceSum
,StartTime
,CASE
WHEN BAL.HolidayBal > (AbsenceSum - TimeTaken) THEN -- HAVE HOL BALANCE AVAILABLE TO USE
CASE
WHEN TimeTaken >= BAL.HolidayBal - (AbsenceSum - TimeTaken) THEN -- NOT ENOUGH HOL TO COVER ENTIRE ABSENCE?
BAL.HolidayBal - (AbsenceSum - TimeTaken) -- NOT ENOUGH, USE WHAT'S LEFT
ELSE
TimeTaken
END -- ELSE USE ENTIRE ABSENCE AS HOL
ELSE
0
END HolidayUsed -- NO AVAILABLE HOL
,CASE WHEN BAL.HolidayBal > (AbsenceSum - TimeTaken) THEN -- HAVE HOL BALANCE AVAILABLE TO USE
(CASE
WHEN TimeTaken >= BAL.HolidayBal - (AbsenceSum - TimeTaken) THEN -- HOL COVERED SOME BUT NOT ALL
CASE
WHEN BAL.PTOBal > 0 THEN --HAVE PTO AVAILABLE
CASE
WHEN BAL.PTOBal >= TimeTaken - (BAL.HolidayBal - (AbsenceSum - TimeTaken)) THEN -- PTO COVERS ALL OF REMAINDER
TimeTaken - (BAL.HolidayBal - (AbsenceSum - TimeTaken))
ELSE --PTO ONLY COVERS SOME
BAL.PTOBal
END
ELSE
0
END
ELSE --HOL COVERED ENTIRE ABSENCE
0
END)
ELSE -- NO HOL TO USE, MOVE TO PTO
CASE
WHEN BAL.PTOBal - ((AbsenceSum - TimeTaken) - BAL.HolidayBal) > 0 THEN -- HAVE PTO TO USE?
CASE
WHEN TimeTaken >= BAL.PTOBal - ((AbsenceSum - TimeTaken) - BAL.HolidayBal) THEN -- HAVE ENOUGH PTO TO COVER ENTIRE ABSENCE?
BAL.PTOBal - ((AbsenceSum - TimeTaken) - BAL.HolidayBal) -- NOT ENOUGH, USE WHAT IS LEFT
ELSE
TimeTaken
END
ELSE
0
END
END AS PTOUsed
FROM (
SELECT EmpId, TimeTaken, ScheduleID, StartTime,
SUM(TimeTaken) OVER (PARTITION BY EmpId ORDER BY ScheduleID, StartTime) AbsenceSum
FROM dbo.Absence
)AB
INNER JOIN dbo.Balance BAL ON BAL.EmpId = AB.EmpId
)A
ORDER BY EmpId
This won't give you separate lines for each case, but it will do the calculation correctly.这不会为每种情况提供单独的行,但它会正确进行计算。 It might be a great interim solution.
这可能是一个很好的临时解决方案。
Create a CTE with the sum of all the time off for the day as follows:创建一个包含当天所有休息时间总和的 CTE,如下所示:
WITH total_absense AS
(
SELECT DISTINCT EmpID, SUM([Time Taken]) OVER(PARTITION BY EmpID)
FROM dbo.Absense
)
Then replace dbo.absense with total_absense in your script.然后在脚本中将 dbo.absense 替换为 total_absense。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.