我试图根据员工迟到的人数来扣除工资。所以我的条件是:如果一名员工连续3天迟到(周五和周六除外 - 每周假期),那么将扣除一天的工资。示例如下,这就是我现在对给定查询的内容:
Name PunchDate Attendance PerDaySal Status
John 2017-05-12 00:00:00.000 W 461.538461538462 Weekly
John 2017-05-13 00:00:00.000 W 461.538461538462 Weekly
John 2017-05-14 09:00:00.000 P 461.538461538462 On Time
John 2017-05-15 09:16:00.000 P 461.538461538462 Late
John 2017-05-16 09:18:00.000 P 461.538461538462 Late
John 2017-05-17 09:20:00.000 P 0 Late -- On 3rd consecutive day
John 2017-05-18 09:26:00.000 P 461.538461538462 Late
John 2017-05-19 00:00:00.000 W 461.538461538462 Weekly
John 2017-05-20 00:00:00.000 W 461.538461538462 Weekly
John 2017-05-21 09:18:00.000 P 461.538461538462 Late
John 2017-05-22 09:28:00.000 P 0 Late -- On the next 3rd consecutive day (Possibly 6th)
John 2017-05-23 09:28:00.000 P 461.538461538462 Late
在上文中,当连续第三天的出勤延迟计数时,则进行扣除。再次,让我提醒一下,这必须在星期五和星期六之外排除。我可以显示已计算的晚数和每周假期,但不确定如何继续扣除。我打算做一张桌子' Deduction'如果我没有弄错的话,为了扣除目的,将日期存储如下:
ID Days
1 3 ---- On 3rd late count, PerDaySal 0
2 6 ---- On 6th late count, PerDaySal 0 and so on
但是对于特定月份(即使每3天),如何验证逻辑?我尝试了一个愚蠢的(虽然没有解决方案):
SELECT k.NAME AS Employee, m.PunchDate,
(CASE WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' THEN 'W' ELSE m.Status END)
AS Attendance,
(CASE WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' THEN 0 ELSE (k.SALARY / 26) END)
AS PerDaySal,
(CASE WHEN CONVERT(CHAR(8), m.PunchDate, 108) > '09:15:00' THEN 'Late'
WHEN CONVERT(CHAR(8), m.PunchDate, 108) >= '09:00:00' AND CONVERT(CHAR(8), m.PunchDate, 108) <= '09:15:00' THEN 'On Time'
WHEN o.WeekName = 'Friday' OR o.WeekName = 'Saturday' AND CONVERT(CHAR(8), m.PunchDate, 108) <= '00:00:00' THEN 'Weekly' END) AS Status
--The silly one - (CASE WHEN COUNT(CONVERT(CHAR(8), m.PunchDate, 108) > '09:15:00') > 3 THEN 0 ELSE (k.SALARY / 26) END) AS PerDaySal
FROM @Attendances m INNER JOIN @Employee k ON k.ID = m.EmpId
LEFT JOIN @Weekly o ON o.WeekDate = m.PunchDate
GROUP BY k.NAME, m.PunchDate, m.Status, k.Salary, o.WeekName
以下是包含示例数据的表结构:
declare @Attendances table (Id int not null identity(1,1) primary key,EmpId int,PunchDate datetime,Status nvarchar(4));
insert into @Attendances([EmpId],[PunchDate],[Status]) values
(2,cast(0x0000A77200000000 as datetime),N'A')
,(2,cast(0x0000A77100000000 as datetime),N'A')
,(2,cast(0x0000A776009A5BA0 as datetime),N'P')
,(2,cast(0x0000A775009450C0 as datetime),N'P')
,(2,cast(0x0000A77400982920 as datetime),N'P')
,(2,cast(0x0000A773009450C0 as datetime),N'P');
declare @Employee table (ID int not null primary key,NAME nvarchar(50),ADDRESS nvarchar(max),SALARY float);
insert @Employee([ID], [NAME], [ADDRESS], [SALARY]) values
(1, N'John', N'Germany', 12000)
,(2, N'Jack', N'France', 14000);
declare @Weekly table (WeekID int not null primary key,WeekNAME nvarchar(20),WeekDate datetime,Status nvarchar(10));
insert @Weekly([WeekID], [WeekName], [WeekDate], [Status]) values
(1, N'Friday', CAST(0x0000A77100000000 AS DateTime), N'W')
,(2, N'Saturday', CAST(0x0000A77200000000 AS DateTime), N'W');
答案 0 :(得分:2)
使用您的示例表而不是多个表,使用公共表表达式和具有case
表达式的窗口函数,如果在星期五或星期六按照问题规范,则不计算一天的延迟时间写这篇文章。
;with cte as (
select *
, rn = row_number() over (partition by Name order by punchDate)
, DayName = datename(weekday,punchdate)
, LateDays = (select sum(
case when datename(weekday,punchdate) not in ('Friday','Saturday') and [Status]='Late'
then 1 else 0 end
)
from t i
where i.Name = t.Name and i.PunchDate <= t.PunchDate
)
from t
)
select
cte.Name
, cte.PunchDate
, cte.DayName
, cte.Attendance
, PerDaysSal = case when z.rn is not null then 0
else cte.PerDaySal end
, cte.Status
, cte.rn
, cte.LateDays
from cte
left join (
select i.Name, rn=min(i.rn)
from cte i
where i.LateDays > 0
and i.LateDays % 3 = 0
group by Name, LateDays
) z
on cte.Name = z.Name
and cte.rn = z.rn
rextester演示:http://rextester.com/ETOI35350
返回:
+------+---------------------+-----------+------------+---------------+---------+----+----------+
| Name | PunchDate | DayName | Attendance | PerDaysSal | Status | rn | LateDays |
+------+---------------------+-----------+------------+---------------+---------+----+----------+
| John | 12.05.2017 00:00:00 | Friday | W | 461,538461538 | Weekly | 1 | 0 |
| John | 13.05.2017 00:00:00 | Saturday | W | 461,538461538 | Weekly | 2 | 0 |
| John | 14.05.2017 00:00:00 | Sunday | P | 461,538461538 | On Time | 3 | 0 |
| John | 15.05.2017 00:00:00 | Monday | P | 461,538461538 | Late | 4 | 1 |
| John | 16.05.2017 00:00:00 | Tuesday | P | 461,538461538 | Late | 5 | 2 |
| John | 17.05.2017 00:00:00 | Wednesday | P | 0,000000000 | Late | 6 | 3 |
| John | 18.05.2017 00:00:00 | Thursday | P | 461,538461538 | Late | 7 | 4 |
| John | 19.05.2017 00:00:00 | Friday | W | 461,538461538 | Weekly | 8 | 4 |
| John | 20.05.2017 00:00:00 | Saturday | P | 461,538461538 | Late | 9 | 4 |
| John | 21.05.2017 00:00:00 | Sunday | P | 461,538461538 | On Time | 10 | 4 |
| John | 22.05.2017 00:00:00 | Monday | P | 461,000000000 | Late | 11 | 5 |
| John | 23.05.2017 00:00:00 | Tuesday | P | 0,000000000 | Late | 12 | 6 |
+------+---------------------+-----------+------------+---------------+---------+----+----------+
在使用实际表时,应使用Name
对EmpId
进行分区,而不是按id
进行分区。您还可以使用出席时的row_number()
代替用于对行进行编号的If GetProcessTimes(lProcessID, lcreationtime.Value, lexittime.Value, lkerneltime.Value, lusertime.Value) Then
。