我正在尝试使用SQL来缩短工作时间,但我不能总结它。总和需要按升序排列,当达到边界极限时,它会继续在另一列或行中求和。
我的数据是这样的:
Employee_Id | Date | Overtime_Day | Overtime_Night
48 | 05/03/2014 | 3 hours | 4 hours
48 | 05/04/2014 | 9 hours | 1 hours
48 | 05/10/2014 | 1 hours | 1 hours
48 | 05/20/2014 | 9 hours | 4 hours
| |= 22 hours | = 10 hours
SUM的边界是这样的:
Overtime (Day+Night) 50%: from 0 to 15
Overtime (Day+Night) 100%: > 15
但我也需要知道它是白天还是黑夜。
Overtime 50% is all hours from 0 to 15, no matter if it's day or night:
3 hours [05/03/2014] [Day]
4 hours [05/03/2014] [Night]
8 hours [05/04/2014] [Day] (2 hours is left for this day, left hours and next hours will be 100%)
Overtime 100% is all hours above 15:
1 hours [05/04/2014] [Day]
1 hours [05/04/2014] [Night]
1 hours [05/10/2014] [Day]
1 hours [05/10/2014] [Night]
9 hours [05/20/2014] [Day]
4 hours [05/20/2014] [Night]
然后我有:
Overtime 50% day: 11 hrs
Overtime 50% night: 4 hrs
Overtime 100% day: 11 hrs
Overtime 100% night: 6 hrs
我想要的结果
Employee_Id | Overtime_Day_50% | Overtime_Night_50% | Overtime_Day_100% | Overtime_Night_100%
48 | 11 hours | 4 hours | 11 hrs | 6 hrs
或者
Employee_Id | Type | Hours
48 | Overtime_Day_50% | 11 hours
48 | Overtime_Night_50% | 4 hours
48 | Overtime_Day_100% | 11 hours
48 | Overtime_Night_100% | 6 hours
(行方式或列方式无关紧要)
很抱歉,如果我没有说清楚,我真的不知道是否可以用SQL来完成这个计算。
任何想法都将不胜感激。 谢谢!
修改
我有这个SELECT,我可以得到所有加班50%和所有加班100%,但有了这个我不能分开什么是白天和什么是夜班。
WITH DATA AS (
SELECT 48 AS EMPLOYEE_ID, '05/03/2014' AS "DATE", 3 AS OVERTIME_DAY, 4 AS OVERTIME_NIGHT FROM DUAL UNION
SELECT 48 AS EMPLOYEE_ID, '05/04/2014' AS "DATE", 9 AS OVERTIME_DAY, 1 AS OVERTIME_NIGHT FROM DUAL UNION
SELECT 48 AS EMPLOYEE_ID, '05/10/2014' AS "DATE", 1 AS OVERTIME_DAY, 1 AS OVERTIME_NIGHT FROM DUAL UNION
SELECT 48 AS EMPLOYEE_ID, '05/20/2014' AS "DATE", 9 AS OVERTIME_DAY, 4 AS OVERTIME_NIGHT FROM DUAL
)
SELECT
EMPLOYEE_ID,
CASE WHEN SUM(OVERTIME_DAY + OVERTIME_NIGHT) >= 15 THEN
15
ELSE
SUM(OVERTIME_DAY + OVERTIME_NIGHT)
END AS OVERTIME_50,
GREATEST(0,SUM(OVERTIME_DAY + OVERTIME_NIGHT) - 15) AS OVERTIME_100
FROM DATA
GROUP BY EMPLOYEE_ID
结果:
Employeed_Id | OVERTIME_50 | OVERTIME_100
48 | 15 | 17
答案 0 :(得分:1)
如果无论白天或晚上计算加班时间,为什么不预先计算每组(白天/黑夜)和总计每日总计的总计。无论如何,支付将在支付期结束时完成。会不会像......
SELECT
PreQry.*,
PreQry.TotalHours,
CASE when PreQry.TotalHours <= 15
then PreQry.TotalHours
ELSE 15 end as OTAt50Pcnt,
CASE when PreQry.TotalHours <= 15
then 0
ELSE PreQry.TotalHours - 15 end as OTAt100Pcnt
from
( select
tc.Employee_ID,
SUM( tc.overtime_day + tc.overtime_night ) as totalHours,
SUM( tc.overtime_day ) as totalOTDay,
SUM( tc.overtime_night ) as totalOTNight
from
TimeCards tc
group by
tc.Employee_ID ) PreQry
这会产生类似
的内容Employee_Id TotalHours Total Day O/T Total Night O/T O/T at 50% O/T at 100%
48 32 22 hours 10 hours 15 hrs 17 hrs
我认为这是一个更可行的解决方案,但仅提供作为Oracle日常汇总的替代方案。我确信具有更深入经验的人可能会提供更准确的服务。
答案 1 :(得分:1)
使用与原始格式相同的数据,即添加新列而不是新行,我们可以获得
With D AS (
Select Employee_Id, "Date", Overtime_Day, Overtime_Night
, SUM(Overtime_Day + Overtime_Night)
OVER (ORDER BY "Date") - Overtime_Night Total_Day
, SUM(Overtime_Day + Overtime_Night)
OVER (ORDER BY "Date") Total_Night
From Data
)
SELECT Employee_Id
, SUM(Case When Total_Day < 15 Then Overtime_Day
When Total_Day < 15 + Overtime_Day
Then Overtime_Day - (Total_Day - 15)
Else 0
END) Overtime_Day_50
, SUM(Case When Total_Night < 15 Then Overtime_Night
When Total_Night < 15 + Overtime_Night
Then Overtime_Night - (Total_Night - 15)
Else 0
END) Overtime_Night_50
, SUM(Case When Total_Day < 15 Then 0
When Total_Day < 15 + Overtime_Day Then Total_Day - 15
When Total_Day > 15 Then Overtime_Day
END) Overtime_Day_100
, SUM(Case When Total_Night < 15 Then 0
When Total_Night < 15 + Overtime_Night Then Total_Night - 15
When Total_Night > 15 Then Overtime_Night
END) Overtime_Night_100
FROM D
GROUP BY Employee_Id
在CTE中,计算当天和晚上加班的滚动总数,在当天的总加班时间公式中减去Overtime_Night
,得到上一次加班和{{当前行的1}}
在主查询中,Overtime_Day
使用“简单”算法来计算值:
100%的部分正好相反
要有一个更通用的案例,如在OP的评论中,可以创建其他组,如
CASE
使用 , SUM(Case When Total_Day < %bStart% Then 0
When Total_Day < %bStart% + Overtime_Day Then Total_Day - %bStart%
When Total_Day < %bEnd% And Total_Day > %bStart% Then Overtime_Day
When Total_Day < %bEnd% + Overtime_Day Then Overtime_Day - (Total_Day - %bEnd%)
Else 0
END) Overtime_Day_60
, SUM(Case When Total_Night < %bStart% Then 0
When Total_Night < %bStart% + Overtime_Night Then Total_Night - %bStart%
When Total_Night < %bEnd% And Total_Night > %bStart% Then Overtime_Night
When Total_Night < %bEnd% + Overtime_Night Then Overtime_Night - (Total_Night - %bStart%)
Else 0
END) Overtime_Night_60
和%bStart%
作为块的起始值和结束值,但它不会非常灵活,使用两个以上的块,不同的方法更好,并且它还允许从查询中删除幻数以将它们移动到表中
%bEnd%
SQLFiddle demo ,数据已更改为白天和晚上都会更改块。
所有条件都是检查边界的不平等。
输出格式为
With D AS (
SELECT Employee_Id, "Date", Overtime_Day, Overtime_Night
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date")
- (Overtime_Day + Overtime_Night) Total_Begin
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date")
- Overtime_Night Total_Day
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date") Total_Night
FROM Data
), Block AS (
SELECT 1 ID, 'Overtime_50' Name, 0 bStart, 15 bEnd FROM DUAL
UNION ALL
SELECT 2, 'Overtime_60', 15, 20 FROM DUAL
UNION ALL
SELECT 3, 'Overtime_100', 20, 999 FROM DUAL
)
SELECT Employee_Id
, block.Name
, SUM(CASE WHEN Total_Begin < bStart AND Total_Day > bStart THEN Total_Day - bStart
WHEN Total_Day < bStart THEN 0
WHEN Total_Day <= bEnd THEN OverTime_Day
WHEN Total_Begin < bEnd AND Total_Day > bEnd THEN bEnd - Total_Begin
END) Overtime_Day
, SUM(CASE WHEN Total_Day >= bStart AND Total_Night < bEnd THEN Overtime_Night
WHEN Total_Begin < bEnd AND Total_Day > bEnd THEN 0
WHEN Total_Day > bStart AND Total_Night > bEnd THEN bEnd - Total_Day
WHEN Total_Day < bStart AND Total_Night > bStart THEN Total_Night - bStart
END) Overtime_Night
FROM D
INNER JOIN Block ON
(Total_Begin < bStart AND Total_Night > bStart)
OR (Total_Begin >= bStart AND Total_Begin < bEnd)
GROUP BY Employee_Id, block.Name, block.ID
ORDER BY block.ID
与原始OP输出请求略有不同,但如果有必要,从这里开始并不困难。
如果你想在一排&amp;多列格式,只需使用Employee_Id | Name | Overtime_Day | Overtime_Night
48 | Overtime_50 | 11 | 4
48 | Overtime_60 | 2 | 3
48 | Overtime_100 | 9 | 5
运算符。
PIVOT
输出格式为
With D AS (
SELECT Employee_Id, "Date", Overtime_Day, Overtime_Night
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date")
- (Overtime_Day + Overtime_Night) Total_Begin
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date")
- Overtime_Night Total_Day
, SUM(Overtime_Day + Overtime_Night) OVER (ORDER BY "Date") Total_Night
FROM Data
), Block AS (
SELECT 1 ID, 'Overtime_50' Name, 0 bStart, 15 bEnd FROM DUAL
UNION ALL
SELECT 2, 'Overtime_60', 15, 20 FROM DUAL
UNION ALL
SELECT 3, 'Overtime_100', 20, 999 FROM DUAL
)
SELECT * FROM (
SELECT Employee_Id
, block.Name
, SUM(CASE WHEN Total_Begin < bStart AND Total_Day > bStart THEN Total_Day - bStart
WHEN Total_Day < bStart THEN 0
WHEN Total_Day <= bEnd THEN OverTime_Day
WHEN Total_Begin < bEnd AND Total_Day > bEnd THEN bEnd - Total_Begin
END) Overtime_Day
, SUM(CASE WHEN Total_Day >= bStart AND Total_Night < bEnd THEN Overtime_Night
WHEN Total_Begin < bEnd AND Total_Day > bEnd THEN 0
WHEN Total_Day > bStart AND Total_Night > bEnd THEN bEnd - Total_Day
WHEN Total_Day < bStart AND Total_Night > bStart THEN Total_Night - bStart
END) Overtime_Night
FROM D
INNER JOIN Block ON
(Total_Begin < bStart AND Total_Night > bStart)
OR (Total_Begin >= bStart AND Total_Begin < bEnd)
GROUP BY Employee_Id, block.Name, block.ID
ORDER BY block.ID
)PIVOT (SUM(OVERTIME_DAY) AS Day, SUM(OVERTIME_NIGHT) AS Night FOR (Name) in ('Overtime_50' as Overtime_50,'Overtime_60' as Overtime_60,'Overtime_100' as Overtime_100))